Merge "Add WebView Tracing API."
diff --git a/Android.bp b/Android.bp
index 2ea4894..015e59f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12,6 +12,645 @@
// 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/slice/ISliceListener.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",
+ "core/java/com/android/server/DropboxLogTags.logtags",
+ "core/java/org/chromium/arc/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 {
@@ -39,34 +678,23 @@
"-Werror",
"-Wno-unused-parameter",
],
+
+ srcs: [
+ "core/proto/**/*.proto",
+ "libs/incident/**/*.proto",
+ "tools/streaming_proto/stream.proto",
+ ],
+
target: {
host: {
proto: {
type: "full",
},
- srcs: [
- "core/proto/**/*.proto",
- "libs/incident/**/*.proto",
- "tools/streaming_proto/stream.proto",
- ],
},
android: {
proto: {
type: "lite",
},
- // We only build the protos that are optimized for the lite
- // runtime, as well as the only protos that are actually
- // needed by the device.
- srcs: [
- "core/proto/android/os/cpufreq.proto",
- "core/proto/android/os/cpuinfo.proto",
- "core/proto/android/os/kernelwake.proto",
- "core/proto/android/os/pagetypeinfo.proto",
- "core/proto/android/os/procrank.proto",
- "core/proto/android/os/system_properties.proto",
- "core/proto/android/service/graphicsstats.proto",
- "tools/streaming_proto/stream.proto",
- ],
shared: {
enabled: false,
},
diff --git a/Android.mk b/Android.mk
index 7a3c46d..d4a1dcf 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,647 +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/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 \
-
-# 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.
# ============================================================
@@ -695,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 \
@@ -744,6 +96,8 @@
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/app/slice/ISliceListener.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 \
@@ -906,85 +260,77 @@
# 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 := \
- test-base/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))
+framework_base_android_test_runner_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,\
+ 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_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.
@@ -993,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 \
@@ -1114,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)
@@ -1139,11 +486,46 @@
include $(BUILD_APIDIFF)
+# Hack to get diffs included in docs output
+out_zip := $(OUT_DOCS)/$(LOCAL_MODULE)-docs.zip
+$(out_zip): $(full_target)
+
+# ==== 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)
+
+# Hack to get diffs included in docs output
+out_zip := $(OUT_DOCS)/$(LOCAL_MODULE)-docs.zip
+$(out_zip): $(full_target)
+
# ==== 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)
@@ -1169,7 +551,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))
@@ -1177,7 +559,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)
@@ -1205,7 +588,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))
@@ -1213,7 +596,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)
@@ -1242,7 +626,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))
@@ -1250,7 +634,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)
@@ -1272,7 +657,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)
# Run this for checkbuild
checkbuild: doc-comment-check-docs
@@ -1283,7 +668,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)
@@ -1312,14 +698,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)
@@ -1354,6 +740,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)
@@ -1361,7 +791,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)
@@ -1389,7 +820,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)
@@ -1424,7 +856,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)
@@ -1453,7 +886,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)
@@ -1482,7 +916,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)
@@ -1507,7 +942,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)
@@ -1535,7 +971,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)
@@ -1572,7 +1009,7 @@
# ==== java proto device library (for test only) ==============================
include $(CLEAR_VARS)
LOCAL_MODULE := platformprotosnano
-LOCAL_MODULE_TAGS := tests optional
+LOCAL_MODULE_TAGS := tests
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
LOCAL_PROTOC_FLAGS := \
-Iexternal/protobuf/src
@@ -1584,6 +1021,17 @@
include $(BUILD_STATIC_JAVA_LIBRARY)
+# ==== java proto device library (for test only) ==============================
+include $(CLEAR_VARS)
+LOCAL_MODULE := platformprotoslite
+LOCAL_MODULE_TAGS := tests
+LOCAL_PROTOC_OPTIMIZE_TYPE := lite
+LOCAL_PROTOC_FLAGS := \
+ -Iexternal/protobuf/src
+LOCAL_SRC_FILES := \
+ $(call all-proto-files-under, core/proto)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
# Include subdirectory makefiles
# ============================================================
diff --git a/apct-tests/perftests/core/Android.mk b/apct-tests/perftests/core/Android.mk
index f08b402..75cb229 100644
--- a/apct-tests/perftests/core/Android.mk
+++ b/apct-tests/perftests/core/Android.mk
@@ -11,8 +11,9 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
apct-perftests-utils \
- guava \
- legacy-android-test
+ guava
+
+LOCAL_JAVA_LIBRARIES := android.test.base
LOCAL_PACKAGE_NAME := CorePerfTests
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..5653a03 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -16,12 +16,19 @@
package android.text;
+import static android.text.TextDirectionHeuristics.LTR;
+
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
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 +40,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 +76,192 @@
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();
+ }
+ }
+
+ @Test
+ public void testCreate_MeasuredText_NoStyled_Greedy_NoHyphenation() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final PremeasuredText text = PremeasuredText.build(
+ generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, LTR);
+ 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_MeasuredText_NoStyled_Greedy_Hyphenation() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final PremeasuredText text = PremeasuredText.build(
+ generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, LTR);
+ 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_MeasuredText_NoStyled_Balanced_NoHyphenation() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final PremeasuredText text = PremeasuredText.build(
+ generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, LTR);
+ 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_MeasuredText_NoStyled_Balanced_Hyphenation() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final PremeasuredText text = PremeasuredText.build(
+ generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, LTR);
+ 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_MeasuredText_Styled_Greedy_NoHyphenation() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final PremeasuredText text = PremeasuredText.build(
+ generateRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT, LTR);
+ 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 c8c194ed..a01de4f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -292,6 +292,7 @@
field public static final int apduServiceBanner = 16843757; // 0x10103ed
field public static final int apiKey = 16843281; // 0x1010211
field public static final int appCategory = 16844101; // 0x1010545
+ field public static final int appComponentFactory = 16844154; // 0x101057a
field public static final int author = 16843444; // 0x10102b4
field public static final int authorities = 16842776; // 0x1010018
field public static final int autoAdvanceViewId = 16843535; // 0x101030f
@@ -343,6 +344,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
@@ -1469,6 +1471,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
@@ -1502,6 +1506,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
@@ -3948,6 +3953,7 @@
field public static final android.os.Parcelable.Creator<android.app.ActivityManager.RunningAppProcessInfo> CREATOR;
field public static final deprecated int IMPORTANCE_BACKGROUND = 400; // 0x190
field public static final int IMPORTANCE_CACHED = 400; // 0x190
+ field public static final int IMPORTANCE_CANT_SAVE_STATE = 270; // 0x10e
field public static final deprecated int IMPORTANCE_EMPTY = 500; // 0x1f4
field public static final int IMPORTANCE_FOREGROUND = 100; // 0x64
field public static final int IMPORTANCE_FOREGROUND_SERVICE = 125; // 0x7d
@@ -4169,6 +4175,15 @@
ctor public AliasActivity();
}
+ public class AppComponentFactory {
+ ctor public AppComponentFactory();
+ method public android.app.Activity instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Application instantiateApplication(java.lang.ClassLoader, java.lang.String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.content.ContentProvider instantiateProvider(java.lang.ClassLoader, java.lang.String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.content.BroadcastReceiver instantiateReceiver(java.lang.ClassLoader, java.lang.String, android.content.Intent) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Service instantiateService(java.lang.ClassLoader, java.lang.String, android.content.Intent) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ }
+
public class AppOpsManager {
method public int checkOp(java.lang.String, int, java.lang.String);
method public int checkOpNoThrow(java.lang.String, int, java.lang.String);
@@ -4991,7 +5006,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();
@@ -6308,7 +6323,7 @@
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
method public void addUserRestriction(android.content.ComponentName, java.lang.String);
method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
- method public boolean clearApplicationUserData(android.content.ComponentName, java.lang.String, android.app.admin.DevicePolicyManager.OnClearApplicationUserDataListener, android.os.Handler);
+ method public boolean clearApplicationUserData(android.content.ComponentName, java.lang.String, android.app.admin.DevicePolicyManager.OnClearApplicationUserDataListener, java.util.concurrent.Executor);
method public void clearCrossProfileIntentFilters(android.content.ComponentName);
method public deprecated void clearDeviceOwnerApp(java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
@@ -6319,6 +6334,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);
@@ -6338,6 +6354,7 @@
method public java.util.List<java.lang.String> getDelegatedScopes(android.content.ComponentName, java.lang.String);
method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
+ method public java.util.List<java.lang.String> getKeepUninstalledPackages(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
method public int getLockTaskFeatures(android.content.ComponentName);
method public java.lang.String[] getLockTaskPackages(android.content.ComponentName);
@@ -6367,6 +6384,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();
@@ -6377,16 +6395,20 @@
method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
+ method public boolean installExistingPackage(android.content.ComponentName, java.lang.String);
method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean);
method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean, boolean);
method public boolean isActivePasswordSufficient();
method public boolean isAdminActive(android.content.ComponentName);
+ method public boolean isAffiliatedUser();
method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
method public boolean isBackupServiceEnabled(android.content.ComponentName);
method public deprecated boolean isCallerApplicationRestrictionsManagingPackage();
method public boolean isDeviceOwnerApp(java.lang.String);
+ method public boolean isEphemeralUser(android.content.ComponentName);
method public boolean isLockTaskPermitted(java.lang.String);
+ method public boolean isLogoutEnabled();
method public boolean isManagedProfile(android.content.ComponentName);
method public boolean isMasterVolumeMuted(android.content.ComponentName);
method public boolean isNetworkLoggingEnabled(android.content.ComponentName);
@@ -6398,6 +6420,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);
@@ -6425,10 +6448,12 @@
method public void setDelegatedScopes(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+ method public void setKeepUninstalledPackages(android.content.ComponentName, java.util.List<java.lang.String>);
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
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 setLogoutEnabled(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);
@@ -6464,12 +6489,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[]);
@@ -6491,6 +6518,8 @@
field public static final java.lang.String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
field public static final java.lang.String DELEGATION_CERT_INSTALL = "delegation-cert-install";
field public static final java.lang.String DELEGATION_ENABLE_SYSTEM_APP = "delegation-enable-system-app";
+ field public static final java.lang.String DELEGATION_INSTALL_EXISTING_PACKAGE = "delegation-install-existing-package";
+ field public static final java.lang.String DELEGATION_KEEP_UNINSTALLED_PACKAGES = "delegation-keep-uninstalled-packages";
field public static final java.lang.String DELEGATION_PACKAGE_ACCESS = "delegation-package-access";
field public static final java.lang.String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant";
field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
@@ -6544,6 +6573,7 @@
field public static final int KEYGUARD_DISABLE_TRUST_AGENTS = 16; // 0x10
field public static final int KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS = 8; // 0x8
field public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1; // 0x1
+ field public static final int LEAVE_ALL_SYSTEM_APPS_ENABLED = 16; // 0x10
field public static final int LOCK_TASK_FEATURE_GLOBAL_ACTIONS = 16; // 0x10
field public static final int LOCK_TASK_FEATURE_HOME = 4; // 0x4
field public static final int LOCK_TASK_FEATURE_KEYGUARD = 32; // 0x20
@@ -6765,6 +6795,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
@@ -6993,11 +7024,14 @@
field public static final java.lang.String HINT_LARGE = "large";
field public static final java.lang.String HINT_LIST = "list";
field public static final java.lang.String HINT_LIST_ITEM = "list_item";
+ field public static final java.lang.String HINT_MAX = "max";
field public static final java.lang.String HINT_NO_TINT = "no_tint";
field public static final java.lang.String HINT_PARTIAL = "partial";
field public static final java.lang.String HINT_SELECTED = "selected";
field public static final java.lang.String HINT_TITLE = "title";
+ field public static final java.lang.String SUBTYPE_COLOR = "color";
field public static final java.lang.String SUBTYPE_MESSAGE = "message";
+ field public static final java.lang.String SUBTYPE_SLIDER = "slider";
field public static final java.lang.String SUBTYPE_SOURCE = "source";
}
@@ -7006,12 +7040,16 @@
ctor public Slice.Builder(android.app.slice.Slice.Builder);
method public android.app.slice.Slice.Builder addAction(android.app.PendingIntent, android.app.slice.Slice);
method public android.app.slice.Slice.Builder addAction(android.app.PendingIntent, android.app.slice.Slice, java.lang.String);
- method public android.app.slice.Slice.Builder addColor(int, java.lang.String, java.lang.String...);
- method public android.app.slice.Slice.Builder addColor(int, java.lang.String, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addBundle(android.os.Bundle, java.lang.String, java.lang.String...);
+ method public android.app.slice.Slice.Builder addBundle(android.os.Bundle, java.lang.String, java.util.List<java.lang.String>);
+ method public deprecated android.app.slice.Slice.Builder addColor(int, java.lang.String, java.lang.String...);
+ method public deprecated android.app.slice.Slice.Builder addColor(int, java.lang.String, java.util.List<java.lang.String>);
method public android.app.slice.Slice.Builder addHints(java.lang.String...);
method public android.app.slice.Slice.Builder addHints(java.util.List<java.lang.String>);
method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.lang.String, java.lang.String...);
method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.lang.String, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addInt(int, java.lang.String, java.lang.String...);
+ method public android.app.slice.Slice.Builder addInt(int, java.lang.String, java.util.List<java.lang.String>);
method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.lang.String, java.util.List<java.lang.String>);
method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.lang.String, java.lang.String...);
method public android.app.slice.Slice.Builder addSubSlice(android.app.slice.Slice);
@@ -7027,10 +7065,12 @@
public final class SliceItem implements android.os.Parcelable {
method public int describeContents();
method public android.app.PendingIntent getAction();
- method public int getColor();
+ method public android.os.Bundle getBundle();
+ method public deprecated int getColor();
method public java.lang.String getFormat();
method public java.util.List<java.lang.String> getHints();
method public android.graphics.drawable.Icon getIcon();
+ method public int getInt();
method public android.app.RemoteInput getRemoteInput();
method public android.app.slice.Slice getSlice();
method public java.lang.String getSubType();
@@ -7040,8 +7080,10 @@
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.slice.SliceItem> CREATOR;
field public static final java.lang.String FORMAT_ACTION = "action";
- field public static final java.lang.String FORMAT_COLOR = "color";
+ field public static final java.lang.String FORMAT_BUNDLE = "bundle";
+ field public static final deprecated java.lang.String FORMAT_COLOR = "color";
field public static final java.lang.String FORMAT_IMAGE = "image";
+ field public static final java.lang.String FORMAT_INT = "int";
field public static final java.lang.String FORMAT_REMOTE_INPUT = "input";
field public static final java.lang.String FORMAT_SLICE = "slice";
field public static final java.lang.String FORMAT_TEXT = "text";
@@ -7208,6 +7250,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);
@@ -7218,6 +7261,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
}
}
@@ -7336,6 +7383,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;
@@ -7351,6 +7400,7 @@
field public int resizeMode;
field public int updatePeriodMillis;
field public int widgetCategory;
+ field public int widgetFeatures;
}
}
@@ -9011,6 +9061,7 @@
method public abstract java.io.File[] getExternalMediaDirs();
method public abstract java.io.File getFileStreamPath(java.lang.String);
method public abstract java.io.File getFilesDir();
+ method public java.util.concurrent.Executor getMainExecutor();
method public abstract android.os.Looper getMainLooper();
method public abstract java.io.File getNoBackupFilesDir();
method public abstract java.io.File getObbDir();
@@ -9954,6 +10005,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";
@@ -10065,6 +10117,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);
}
@@ -10368,6 +10421,7 @@
field public static final int FLAG_UPDATED_SYSTEM_APP = 128; // 0x80
field public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 134217728; // 0x8000000
field public static final int FLAG_VM_SAFE_MODE = 16384; // 0x4000
+ field public java.lang.String appComponentFactory;
field public java.lang.String backupAgentName;
field public int category;
field public java.lang.String className;
@@ -10583,6 +10637,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
@@ -10612,7 +10668,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;
}
@@ -11127,9 +11183,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
@@ -11223,9 +11280,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;
}
@@ -11235,6 +11294,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);
}
@@ -15487,6 +15548,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
@@ -15761,6 +15824,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;
@@ -20526,6 +20590,7 @@
method public int getMaxWidth();
method public java.lang.CharSequence getTextForImeAction(int);
method public android.app.Dialog getWindow();
+ method public void hideSoftInputFromInputMethod(int);
method public void hideStatusIcon();
method public void hideWindow();
method public boolean isExtractViewShown();
@@ -20581,10 +20646,16 @@
method public void setCandidatesViewShown(boolean);
method public void setExtractView(android.view.View);
method public void setExtractViewShown(boolean);
+ method public void setInputMethod(java.lang.String);
+ method public void setInputMethodAndSubtype(java.lang.String, android.view.inputmethod.InputMethodSubtype);
method public void setInputView(android.view.View);
+ method public boolean shouldOfferSwitchingToNextInputMethod();
+ method public void showSoftInputFromInputMethod(int);
method public void showStatusIcon(int);
method public void showWindow(boolean);
method public void switchInputMethod(java.lang.String);
+ method public boolean switchToLastInputMethod();
+ method public boolean switchToNextInputMethod(boolean);
method public void updateFullscreenMode();
method public void updateInputViewShown();
field public static final int BACK_DISPOSITION_DEFAULT = 0; // 0x0
@@ -20934,6 +21005,7 @@
method public void onGnssMeasurementsReceived(android.location.GnssMeasurementsEvent);
method public void onStatusChanged(int);
field public static final int STATUS_LOCATION_DISABLED = 2; // 0x2
+ field public static final int STATUS_NOT_ALLOWED = 3; // 0x3
field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
field public static final int STATUS_READY = 1; // 0x1
}
@@ -22032,6 +22104,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();
@@ -25967,6 +26040,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();
@@ -26164,6 +26254,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();
@@ -26189,9 +26280,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
}
@@ -30888,7 +30982,9 @@
ctor public Build.VERSION();
field public static final java.lang.String BASE_OS;
field public static final java.lang.String CODENAME;
+ field public static final int FIRST_SDK_INT;
field public static final java.lang.String INCREMENTAL;
+ field public static final int MIN_SUPPORTED_TARGET_SDK_INT;
field public static final int PREVIEW_SDK_INT;
field public static final java.lang.String RELEASE;
field public static final deprecated java.lang.String SDK;
@@ -33138,6 +33234,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";
@@ -34288,6 +34385,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";
@@ -35954,6 +36053,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";
@@ -37093,6 +37193,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);
@@ -37470,6 +37575,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);
}
@@ -39270,6 +39377,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 {
@@ -39449,6 +39557,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);
@@ -39465,8 +39574,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);
@@ -39474,6 +39585,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);
@@ -39527,6 +39642,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
@@ -39546,6 +39662,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);
@@ -39586,7 +39708,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;
}
@@ -39596,12 +39720,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);
@@ -40119,10 +40246,12 @@
field public static final java.lang.String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string";
field public static final java.lang.String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
field public static final java.lang.String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool";
+ field public static final java.lang.String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
field public static final java.lang.String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
field public static final java.lang.String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
field public static final java.lang.String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
+ field public static final java.lang.String KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL = "show_signal_strength_in_sim_status_bool";
field public static final java.lang.String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
field public static final java.lang.String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
@@ -40741,6 +40870,8 @@
method public int getSimState();
method public int getSimState(int);
method public java.lang.String getSubscriberId();
+ method public int getSubscriptionCarrierId();
+ method public java.lang.String getSubscriptionCarrierName();
method public java.lang.String getVisualVoicemailPackageName();
method public java.lang.String getVoiceMailAlphaTag();
method public java.lang.String getVoiceMailNumber();
@@ -40774,12 +40905,13 @@
method public boolean setPreferredNetworkTypeToGlobal();
method public void setVisualVoicemailSmsFilterSettings(android.telephony.VisualVoicemailSmsFilterSettings);
method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
- method public void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri);
- method public void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean);
+ method public deprecated void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri);
+ method public deprecated void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean);
field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
field public static final java.lang.String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
+ field public static final java.lang.String ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED";
field public static final int APPTYPE_CSIM = 4; // 0x4
field public static final int APPTYPE_ISIM = 5; // 0x5
field public static final int APPTYPE_RUIM = 3; // 0x3
@@ -40804,6 +40936,8 @@
field public static final int DATA_DISCONNECTED = 0; // 0x0
field public static final int DATA_SUSPENDED = 3; // 0x3
field public static final java.lang.String EXTRA_CALL_VOICEMAIL_INTENT = "android.telephony.extra.CALL_VOICEMAIL_INTENT";
+ field public static final java.lang.String EXTRA_CARRIER_ID = "android.telephony.extra.CARRIER_ID";
+ field public static final java.lang.String EXTRA_CARRIER_NAME = "android.telephony.extra.CARRIER_NAME";
field public static final java.lang.String EXTRA_HIDE_PUBLIC_SETTINGS = "android.telephony.extra.HIDE_PUBLIC_SETTINGS";
field public static final java.lang.String EXTRA_INCOMING_NUMBER = "incoming_number";
field public static final java.lang.String EXTRA_IS_REFRESH = "android.telephony.extra.IS_REFRESH";
@@ -40814,6 +40948,7 @@
field public static final java.lang.String EXTRA_STATE_IDLE;
field public static final java.lang.String EXTRA_STATE_OFFHOOK;
field public static final java.lang.String EXTRA_STATE_RINGING;
+ field public static final java.lang.String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID";
field public static final java.lang.String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
field public static final java.lang.String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU";
field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
@@ -40849,6 +40984,7 @@
field public static final int SIM_STATE_PUK_REQUIRED = 3; // 0x3
field public static final int SIM_STATE_READY = 5; // 0x5
field public static final int SIM_STATE_UNKNOWN = 0; // 0x0
+ field public static final int UNKNOWN_CARRIER_ID = -1; // 0xffffffff
field public static final int USSD_ERROR_SERVICE_UNAVAIL = -2; // 0xfffffffe
field public static final int USSD_RETURN_FAILURE = -1; // 0xffffffff
field public static final java.lang.String VVM_TYPE_CVVM = "vvm_type_cvvm";
@@ -42171,6 +42307,27 @@
method public abstract int getSpanTypeId();
}
+ public class PremeasuredText implements android.text.Spanned {
+ method public static android.text.PremeasuredText build(java.lang.CharSequence, android.text.TextPaint, android.text.TextDirectionHeuristic);
+ method public static android.text.PremeasuredText build(java.lang.CharSequence, android.text.TextPaint, android.text.TextDirectionHeuristic, int, int);
+ method public char charAt(int);
+ method public int getEnd();
+ method public android.text.TextPaint getPaint();
+ method public int getParagraphCount();
+ method public int getParagraphEnd(int);
+ method public int getParagraphStart(int);
+ method public int getSpanEnd(java.lang.Object);
+ method public int getSpanFlags(java.lang.Object);
+ method public int getSpanStart(java.lang.Object);
+ method public <T> T[] getSpans(int, int, java.lang.Class<T>);
+ method public int getStart();
+ method public java.lang.CharSequence getText();
+ method public android.text.TextDirectionHeuristic getTextDir();
+ method public int length();
+ method public int nextSpanTransition(int, int, java.lang.Class);
+ method public java.lang.CharSequence subSequence(int, int);
+ }
+
public class Selection {
method public static boolean extendDown(android.text.Spannable, android.text.Layout);
method public static boolean extendLeft(android.text.Spannable, android.text.Layout);
@@ -48949,10 +49106,10 @@
method public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodList();
method public android.view.inputmethod.InputMethodSubtype getLastInputMethodSubtype();
method public java.util.Map<android.view.inputmethod.InputMethodInfo, java.util.List<android.view.inputmethod.InputMethodSubtype>> getShortcutInputMethodsAndSubtypes();
- method public void hideSoftInputFromInputMethod(android.os.IBinder, int);
+ method public deprecated void hideSoftInputFromInputMethod(android.os.IBinder, int);
method public boolean hideSoftInputFromWindow(android.os.IBinder, int);
method public boolean hideSoftInputFromWindow(android.os.IBinder, int, android.os.ResultReceiver);
- method public void hideStatusIcon(android.os.IBinder);
+ method public deprecated void hideStatusIcon(android.os.IBinder);
method public boolean isAcceptingText();
method public boolean isActive(android.view.View);
method public boolean isActive();
@@ -48962,17 +49119,17 @@
method public void sendAppPrivateCommand(android.view.View, java.lang.String, android.os.Bundle);
method public void setAdditionalInputMethodSubtypes(java.lang.String, android.view.inputmethod.InputMethodSubtype[]);
method public boolean setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype);
- method public void setInputMethod(android.os.IBinder, java.lang.String);
- method public void setInputMethodAndSubtype(android.os.IBinder, java.lang.String, android.view.inputmethod.InputMethodSubtype);
- method public boolean shouldOfferSwitchingToNextInputMethod(android.os.IBinder);
+ method public deprecated void setInputMethod(android.os.IBinder, java.lang.String);
+ method public deprecated void setInputMethodAndSubtype(android.os.IBinder, java.lang.String, android.view.inputmethod.InputMethodSubtype);
+ method public deprecated boolean shouldOfferSwitchingToNextInputMethod(android.os.IBinder);
method public void showInputMethodAndSubtypeEnabler(java.lang.String);
method public void showInputMethodPicker();
method public boolean showSoftInput(android.view.View, int);
method public boolean showSoftInput(android.view.View, int, android.os.ResultReceiver);
- method public void showSoftInputFromInputMethod(android.os.IBinder, int);
- method public void showStatusIcon(android.os.IBinder, java.lang.String, int);
- method public boolean switchToLastInputMethod(android.os.IBinder);
- method public boolean switchToNextInputMethod(android.os.IBinder, boolean);
+ method public deprecated void showSoftInputFromInputMethod(android.os.IBinder, int);
+ method public deprecated void showStatusIcon(android.os.IBinder, java.lang.String, int);
+ method public deprecated boolean switchToLastInputMethod(android.os.IBinder);
+ method public deprecated boolean switchToNextInputMethod(android.os.IBinder, boolean);
method public void toggleSoftInput(int, int);
method public void toggleSoftInputFromWindow(android.os.IBinder, int, int);
method public deprecated void updateCursor(android.view.View, int, int, int, int);
@@ -49049,31 +49206,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);
}
@@ -49090,15 +49250,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";
}
@@ -49114,13 +49278,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 {
@@ -49138,12 +49298,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 {
@@ -54902,7 +55064,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();
@@ -56563,6 +56724,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();
@@ -56660,6 +56826,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/system-current.txt b/api/system-current.txt
index 352acfe..30e4cbc 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,13 @@
}
public final class UsageStatsManager {
+ method public int getAppStandbyBucket(java.lang.String);
+ method public java.util.Map<java.lang.String, java.lang.Integer> getAppStandbyBuckets();
method public void setAppStandbyBucket(java.lang.String, int);
+ method public void setAppStandbyBuckets(java.util.Map<java.lang.String, java.lang.Integer>);
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
}
}
@@ -776,13 +785,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;
}
@@ -839,6 +851,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);
@@ -946,6 +959,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 {
@@ -2075,11 +2106,13 @@
method public int getQuality();
method public float getSmallestDisplacement();
method public android.os.WorkSource getWorkSource();
+ method public boolean isLowPowerMode();
method public android.location.LocationRequest setExpireAt(long);
method public android.location.LocationRequest setExpireIn(long);
method public android.location.LocationRequest setFastestInterval(long);
method public void setHideFromAppOps(boolean);
method public android.location.LocationRequest setInterval(long);
+ method public android.location.LocationRequest setLowPowerMode(boolean);
method public android.location.LocationRequest setNumUpdates(int);
method public android.location.LocationRequest setProvider(java.lang.String);
method public android.location.LocationRequest setQuality(int);
@@ -4102,10 +4135,12 @@
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();
method public deprecated boolean getDataEnabled(int);
+ method public boolean getEmergencyCallbackMode();
method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
method public android.os.Bundle getVisualVoicemailSettings();
method public boolean handlePinMmi(java.lang.String);
@@ -4147,6 +4182,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);
@@ -4176,6 +4230,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 {
@@ -4328,6 +4393,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/test-current.txt b/api/test-current.txt
index 8647ed3..3fc5cd6 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
@@ -120,6 +120,7 @@
public class StorageStatsManager {
method public boolean isQuotaSupported(java.util.UUID);
+ method public boolean isReservedSupported(java.util.UUID);
}
}
@@ -162,6 +163,10 @@
method public abstract boolean isPermissionReviewModeEnabled();
}
+ public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+ field public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 32768; // 0x8000
+ }
+
public final class ShortcutInfo implements android.os.Parcelable {
method public boolean isVisibleToPublisher();
}
@@ -425,7 +430,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 +462,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 +501,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 +523,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 +636,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 +993,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/bootanimation/iot/BootParameters.h b/cmds/bootanimation/iot/BootParameters.h
index ff3b018..c10bd44 100644
--- a/cmds/bootanimation/iot/BootParameters.h
+++ b/cmds/bootanimation/iot/BootParameters.h
@@ -48,8 +48,8 @@
struct SavedBootParameters {
int brightness;
int volume;
- ScopedVector<std::string> param_names;
- ScopedVector<std::string> param_values;
+ std::vector<std::unique_ptr<std::string>> param_names;
+ std::vector<std::unique_ptr<std::string>> param_values;
SavedBootParameters();
static void RegisterJSONConverter(
diff --git a/cmds/ime/Android.mk b/cmds/ime/Android.mk
index 6803fc0..ca608e8 100644
--- a/cmds/ime/Android.mk
+++ b/cmds/ime/Android.mk
@@ -3,14 +3,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := imelib
-LOCAL_MODULE_STEM := ime
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
LOCAL_MODULE := ime
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_SRC_FILES := ime
-LOCAL_REQUIRED_MODULES := imelib
include $(BUILD_PREBUILT)
diff --git a/cmds/ime/ime b/cmds/ime/ime
index 1a1fdd9..180dc76 100755
--- a/cmds/ime/ime
+++ b/cmds/ime/ime
@@ -1,8 +1,2 @@
#!/system/bin/sh
-# Script to start "pm" on the device, which has a very rudimentary
-# shell.
-#
-base=/system
-export CLASSPATH=$base/framework/ime.jar
-exec app_process $base/bin com.android.commands.ime.Ime "$@"
-
+exec cmd input_method "$@"
diff --git a/cmds/ime/src/com/android/commands/ime/Ime.java b/cmds/ime/src/com/android/commands/ime/Ime.java
deleted file mode 100644
index 72a0af6..0000000
--- a/cmds/ime/src/com/android/commands/ime/Ime.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.commands.ime;
-
-import com.android.internal.view.IInputMethodManager;
-
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.PrintStreamPrinter;
-import android.util.Printer;
-import android.view.inputmethod.InputMethodInfo;
-
-import java.util.List;
-
-public final class Ime {
- IInputMethodManager mImm;
-
- private String[] mArgs;
- private int mNextArg;
- private String mCurArgData;
-
- private static final String IMM_NOT_RUNNING_ERR =
- "Error: Could not access the Input Method Manager. Is the system running?";
-
- public static void main(String[] args) {
- new Ime().run(args);
- }
-
- public void run(String[] args) {
- if (args.length < 1) {
- showUsage();
- return;
- }
-
- mImm = IInputMethodManager.Stub.asInterface(ServiceManager.getService("input_method"));
- if (mImm == null) {
- System.err.println(IMM_NOT_RUNNING_ERR);
- return;
- }
-
- mArgs = args;
- String op = args[0];
- mNextArg = 1;
-
- if ("list".equals(op)) {
- runList();
- return;
- }
-
- if ("enable".equals(op)) {
- runSetEnabled(true);
- return;
- }
-
- if ("disable".equals(op)) {
- runSetEnabled(false);
- return;
- }
-
- if ("set".equals(op)) {
- runSet();
- return;
- }
-
- if (op != null) {
- System.err.println("Error: unknown command '" + op + "'");
- }
- showUsage();
- }
-
- /**
- * Execute the list sub-command.
- */
- private void runList() {
- String opt;
- boolean all = false;
- boolean brief = false;
- while ((opt=nextOption()) != null) {
- if (opt.equals("-a")) {
- all = true;
- } else if (opt.equals("-s")) {
- brief = true;
- } else {
- System.err.println("Error: Unknown option: " + opt);
- showUsage();
- return;
- }
- }
-
-
- List<InputMethodInfo> methods;
- if (!all) {
- try {
- methods = mImm.getEnabledInputMethodList();
- } catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(IMM_NOT_RUNNING_ERR);
- return;
- }
- } else {
- try {
- methods = mImm.getInputMethodList();
- } catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(IMM_NOT_RUNNING_ERR);
- return;
- }
- }
-
- if (methods != null) {
- Printer pr = new PrintStreamPrinter(System.out);
- for (int i=0; i<methods.size(); i++) {
- InputMethodInfo imi = methods.get(i);
- if (brief) {
- System.out.println(imi.getId());
- } else {
- System.out.println(imi.getId() + ":");
- imi.dump(pr, " ");
- }
- }
- }
- }
-
- private void runSetEnabled(boolean state) {
- String id = nextArg();
- if (id == null) {
- System.err.println("Error: no input method ID specified");
- showUsage();
- return;
- }
-
- try {
- boolean res = mImm.setInputMethodEnabled(id, state);
- if (state) {
- System.out.println("Input method " + id + ": "
- + (res ? "already enabled" : "now enabled"));
- } else {
- System.out.println("Input method " + id + ": "
- + (res ? "now disabled" : "already disabled"));
- }
- } catch (IllegalArgumentException e) {
- System.err.println("Error: " + e.getMessage());
- return;
- } catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(IMM_NOT_RUNNING_ERR);
- return;
- }
- }
-
- private void runSet() {
- String id = nextArg();
- if (id == null) {
- System.err.println("Error: no input method ID specified");
- showUsage();
- return;
- }
-
- try {
- mImm.setInputMethod(null, id);
- System.out.println("Input method " + id + " selected");
- } catch (IllegalArgumentException e) {
- System.err.println("Error: " + e.getMessage());
- return;
- } catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(IMM_NOT_RUNNING_ERR);
- return;
- }
- }
-
- private String nextOption() {
- if (mNextArg >= mArgs.length) {
- return null;
- }
- String arg = mArgs[mNextArg];
- if (!arg.startsWith("-")) {
- return null;
- }
- mNextArg++;
- if (arg.equals("--")) {
- return null;
- }
- if (arg.length() > 1 && arg.charAt(1) != '-') {
- if (arg.length() > 2) {
- mCurArgData = arg.substring(2);
- return arg.substring(0, 2);
- } else {
- mCurArgData = null;
- return arg;
- }
- }
- mCurArgData = null;
- return arg;
- }
-
- private String nextOptionData() {
- if (mCurArgData != null) {
- return mCurArgData;
- }
- if (mNextArg >= mArgs.length) {
- return null;
- }
- String data = mArgs[mNextArg];
- mNextArg++;
- return data;
- }
-
- private String nextArg() {
- if (mNextArg >= mArgs.length) {
- return null;
- }
- String arg = mArgs[mNextArg];
- mNextArg++;
- return arg;
- }
-
- private static void showUsage() {
- System.err.println("usage: ime list [-a] [-s]");
- System.err.println(" ime enable ID");
- System.err.println(" ime disable ID");
- System.err.println(" ime set ID");
- System.err.println("");
- System.err.println("The list command prints all enabled input methods. Use");
- System.err.println("the -a option to see all input methods. Use");
- System.err.println("the -s option to see only a single summary line of each.");
- System.err.println("");
- System.err.println("The enable command allows the given input method ID to be used.");
- System.err.println("");
- System.err.println("The disable command disallows the given input method ID from use.");
- System.err.println("");
- System.err.println("The set command switches to the given input method ID.");
- }
-}
diff --git a/cmds/incident_helper/Android.bp b/cmds/incident_helper/Android.bp
index 2ef0371..d7b6d69 100644
--- a/cmds/incident_helper/Android.bp
+++ b/cmds/incident_helper/Android.bp
@@ -38,6 +38,7 @@
cc_test {
name: "incident_helper_test",
+ test_suites: ["device-tests"],
defaults: ["incident_helper_defaults"],
local_include_dirs: ["src/"],
@@ -49,12 +50,15 @@
"testdata/*",
],
- shared_libs: [
- "libprotobuf-cpp-full",
- ],
-
static_libs: [
"libgmock",
"libplatformprotos"
],
+
+ shared_libs: [
+ "libprotobuf-cpp-full"
+ ],
+ proto: {
+ type: "full",
+ },
}
diff --git a/cmds/incident_helper/AndroidTest.xml b/cmds/incident_helper/AndroidTest.xml
new file mode 100644
index 0000000..6d242bc
--- /dev/null
+++ b/cmds/incident_helper/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?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="Config for incident_helper_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="incident_helper_test->/data/nativetest/incident_helper_test" />
+ <option name="push" value="testdata->/data/nativetest/testdata" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/nativetest" />
+ <option name="module-name" value="incident_helper_test" />
+ </test>
+</configuration>
diff --git a/cmds/incident_helper/src/ih_util.cpp b/cmds/incident_helper/src/ih_util.cpp
index db4f586..4bf956a 100644
--- a/cmds/incident_helper/src/ih_util.cpp
+++ b/cmds/incident_helper/src/ih_util.cpp
@@ -297,3 +297,82 @@
}
return true;
}
+
+// ================================================================================
+Message::Message(Table* table)
+ :mTable(table),
+ mPreviousField(""),
+ mTokens(),
+ mSubMessages()
+{
+}
+
+Message::~Message()
+{
+}
+
+void
+Message::addSubMessage(uint64_t fieldId, Message* fieldMsg)
+{
+ for (auto iter = mTable->mFields.begin(); iter != mTable->mFields.end(); iter++) {
+ if (iter->second == fieldId) {
+ mSubMessages[iter->first] = fieldMsg;
+ return;
+ }
+ }
+}
+
+bool
+Message::insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value)
+{
+ // If the field name can be found, it means the name is a primitive field.
+ if (mTable->mFields.find(name) != mTable->mFields.end()) {
+ endSession(proto);
+ // The only edge case is for example ro.hardware itself is a message, so a field called "value"
+ // would be defined in proto Ro::Hardware and it must be the first field.
+ if (mSubMessages.find(name) != mSubMessages.end()) {
+ startSession(proto, name);
+ return mSubMessages[name]->insertField(proto, "value", value);
+ } else {
+ return mTable->insertField(proto, name, value);
+ }
+ }
+
+ // Try to find the message field which is the prefix of name, so the value would be inserted
+ // recursively into the submessage.
+ string mutableName = name;
+ for (auto iter = mSubMessages.begin(); iter != mSubMessages.end(); iter++) {
+ string fieldName = iter->first;
+ string prefix = fieldName + "_"; // underscore is the delimiter in the name
+ if (stripPrefix(&mutableName, prefix.c_str())) {
+ if (mPreviousField != fieldName) {
+ endSession(proto);
+ startSession(proto, fieldName);
+ }
+ return mSubMessages[fieldName]->insertField(proto, mutableName, value);
+ }
+ }
+ // Can't find the name in proto definition, handle it separately.
+ return false;
+}
+
+void
+Message::startSession(ProtoOutputStream* proto, const string& name)
+{
+ uint64_t fieldId = mTable->mFields[name];
+ long long token = proto->start(fieldId);
+ mPreviousField = name;
+ mTokens.push(token);
+}
+
+void
+Message::endSession(ProtoOutputStream* proto)
+{
+ if (mPreviousField == "") return;
+ if (mSubMessages.find(mPreviousField) != mSubMessages.end()) {
+ mSubMessages[mPreviousField]->endSession(proto);
+ }
+ proto->end(mTokens.top());
+ mTokens.pop();
+ mPreviousField = "";
+}
diff --git a/cmds/incident_helper/src/ih_util.h b/cmds/incident_helper/src/ih_util.h
index 4a5fe1d..58ef290 100644
--- a/cmds/incident_helper/src/ih_util.h
+++ b/cmds/incident_helper/src/ih_util.h
@@ -18,6 +18,7 @@
#define INCIDENT_HELPER_UTIL_H
#include <map>
+#include <stack>
#include <string>
#include <vector>
@@ -34,7 +35,7 @@
const std::string TAB_DELIMITER = "\t";
const std::string COMMA_DELIMITER = ",";
-// returns true if c is a-zA-Z0-9 or underscore _
+// returns true if c is a-zA-Z0-9 or underscore
bool isValidChar(char c);
// trim the string with the given charset
@@ -102,11 +103,20 @@
};
/**
- * The class contains a mapping between table headers to its field ids.
- * And allow users to insert the field values to proto based on its header name.
+ * The Table class is constructed from two arrays generated by the given message with
+ * option (stream_proto.stream_msg).enable_fields_mapping = true.
+ * The names are each field's names in the message and must corresponding to the header/name of
+ * the text to be parsed, and the ids are the streaming proto encoded field ids.
+ *
+ * This class then allows users to insert the table values to proto based on its header.
+ *
+ * Advance feature: if some fields in the message are enums, user must explicitly add the
+ * mapping from enum name string to its enum values.
*/
+class Message;
class Table
{
+friend class Message;
public:
Table(const char* names[], const uint64_t ids[], const int count);
~Table();
@@ -114,9 +124,12 @@
// Add enum names to values for parsing purpose.
void addEnumTypeMap(const char* field, const char* enumNames[], const int enumValues[], const int enumSize);
- // manually add enum names to values mapping, useful when an Enum type is used by a lot of fields, and there are no name conflicts
+ // Manually add enum names to values mapping, useful when an Enum type is used by
+ // a number of fields, there must not be any enum name conflicts.
void addEnumNameToValue(const char* enumName, const int enumValue);
+ // Based on given name, find the right field id, parse the text value and insert to proto.
+ // Return false if the given name can't be found.
bool insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value);
private:
map<std::string, uint64_t> mFields;
@@ -124,4 +137,47 @@
map<std::string, int> mEnumValuesByName;
};
+/**
+ * Reconstructs a typical proto message given its message Table, adds submessage fields explicitly.
+ * It allows user to insert nested proto values purely by the names. See insertField for detail.
+ */
+class Message
+{
+public:
+ Message(Table* table);
+ ~Message();
+
+ // Reconstructs the typical proto message by adding its message fields.
+ void addSubMessage(uint64_t fieldId, Message* fieldMsg);
+
+ // Inserts value if the given name has the corresponding field in its message and return true.
+ // It will recursively search the name in submessages and find the correct field to insert.
+ // For example, when the name is dalvik_vm_heapsize, and the message's corresponding proto is:
+ // message Properties {
+ // message DalvikVm {
+ // int32 heapsize = 1;
+ // bool usejit = 2;
+ // }
+ // DalvikVm dalvik_vm = 1;
+ // string hack_in = 2;
+ // }
+ // The value will be inserted into field heapsize in dalvik_vm submessage.
+ //
+ // Also value belongs to same submessage MUST be inserted contiguously.
+ // For example, dalvik_vm_usejit must be inserted directly after dalvik_vm_heapsize, otherwise
+ // if hack_in attempts to be inserted before dalvik_vm_usejit, value of usejit isn't added as expected.
+ bool insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value);
+
+ // Starts a new message field proto session.
+ void startSession(ProtoOutputStream* proto, const string& name);
+
+ // Ends the previous message field proto session.
+ void endSession(ProtoOutputStream* proto);
+private:
+ Table* mTable;
+ std::string mPreviousField;
+ stack<long long> mTokens;
+ map<std::string, Message*> mSubMessages;
+};
+
#endif // INCIDENT_HELPER_UTIL_H
diff --git a/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp b/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp
index ee5feb0..23393da0 100644
--- a/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp
+++ b/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp
@@ -45,11 +45,130 @@
string line;
string name; // the name of the property
string value; // the string value of the property
-
ProtoOutputStream proto;
- Table table(SystemPropertiesProto::_FIELD_NAMES, SystemPropertiesProto::_FIELD_IDS, SystemPropertiesProto::_FIELD_COUNT);
- table.addEnumNameToValue("running", SystemPropertiesProto::STATUS_RUNNING);
- table.addEnumNameToValue("stopped", SystemPropertiesProto::STATUS_STOPPED);
+ vector<pair<string, string>> extras;
+
+ Table sysPropTable(SystemPropertiesProto::_FIELD_NAMES,
+ SystemPropertiesProto::_FIELD_IDS,
+ SystemPropertiesProto::_FIELD_COUNT);
+ Message sysProp(&sysPropTable);
+
+ Table aacDrcTable(SystemPropertiesProto::AacDrc::_FIELD_NAMES,
+ SystemPropertiesProto::AacDrc::_FIELD_IDS,
+ SystemPropertiesProto::AacDrc::_FIELD_COUNT);
+ Message aacDrc(&aacDrcTable);
+ sysProp.addSubMessage(SystemPropertiesProto::AAC_DRC, &aacDrc);
+
+ Table aaudioTable(SystemPropertiesProto::Aaudio::_FIELD_NAMES,
+ SystemPropertiesProto::Aaudio::_FIELD_IDS,
+ SystemPropertiesProto::Aaudio::_FIELD_COUNT);
+ Message aaudio(&aaudioTable);
+ sysProp.addSubMessage(SystemPropertiesProto::AAUDIO, &aaudio);
+
+ Table cameraTable(SystemPropertiesProto::Camera::_FIELD_NAMES,
+ SystemPropertiesProto::Camera::_FIELD_IDS,
+ SystemPropertiesProto::Camera::_FIELD_COUNT);
+ Message camera(&cameraTable);
+ sysProp.addSubMessage(SystemPropertiesProto::CAMERA, &camera);
+
+ Table dalvikVmTable(SystemPropertiesProto::DalvikVm::_FIELD_NAMES,
+ SystemPropertiesProto::DalvikVm::_FIELD_IDS,
+ SystemPropertiesProto::DalvikVm::_FIELD_COUNT);
+ Message dalvikVm(&dalvikVmTable);
+ sysProp.addSubMessage(SystemPropertiesProto::DALVIK_VM, &dalvikVm);
+
+ Table initSvcTable(SystemPropertiesProto::InitSvc::_FIELD_NAMES,
+ SystemPropertiesProto::InitSvc::_FIELD_IDS,
+ SystemPropertiesProto::InitSvc::_FIELD_COUNT);
+ initSvcTable.addEnumNameToValue("running", SystemPropertiesProto::InitSvc::STATUS_RUNNING);
+ initSvcTable.addEnumNameToValue("stopped", SystemPropertiesProto::InitSvc::STATUS_STOPPED);
+ Message initSvc(&initSvcTable);
+ sysProp.addSubMessage(SystemPropertiesProto::INIT_SVC, &initSvc);
+
+ Table logTable(SystemPropertiesProto::Log::_FIELD_NAMES,
+ SystemPropertiesProto::Log::_FIELD_IDS,
+ SystemPropertiesProto::Log::_FIELD_COUNT);
+ Message logMsg(&logTable);
+ sysProp.addSubMessage(SystemPropertiesProto::LOG, &logMsg);
+
+ Table persistTable(SystemPropertiesProto::Persist::_FIELD_NAMES,
+ SystemPropertiesProto::Persist::_FIELD_IDS,
+ SystemPropertiesProto::Persist::_FIELD_COUNT);
+ Message persist(&persistTable);
+ sysProp.addSubMessage(SystemPropertiesProto::PERSIST, &persist);
+
+ Table pmDexoptTable(SystemPropertiesProto::PmDexopt::_FIELD_NAMES,
+ SystemPropertiesProto::PmDexopt::_FIELD_IDS,
+ SystemPropertiesProto::PmDexopt::_FIELD_COUNT);
+ Message pmDexopt(&pmDexoptTable);
+ sysProp.addSubMessage(SystemPropertiesProto::PM_DEXOPT, &pmDexopt);
+
+ Table roTable(SystemPropertiesProto::Ro::_FIELD_NAMES,
+ SystemPropertiesProto::Ro::_FIELD_IDS,
+ SystemPropertiesProto::Ro::_FIELD_COUNT);
+ Message ro(&roTable);
+
+ Table bootTable(SystemPropertiesProto::Ro::Boot::_FIELD_NAMES,
+ SystemPropertiesProto::Ro::Boot::_FIELD_IDS,
+ SystemPropertiesProto::Ro::Boot::_FIELD_COUNT);
+ Message boot(&bootTable);
+ ro.addSubMessage(SystemPropertiesProto::Ro::BOOT, &boot);
+
+ Table bootimageTable(SystemPropertiesProto::Ro::BootImage::_FIELD_NAMES,
+ SystemPropertiesProto::Ro::BootImage::_FIELD_IDS,
+ SystemPropertiesProto::Ro::BootImage::_FIELD_COUNT);
+ Message bootimage(&bootimageTable);
+ ro.addSubMessage(SystemPropertiesProto::Ro::BOOTIMAGE, &bootimage);
+
+ Table buildTable(SystemPropertiesProto::Ro::Build::_FIELD_NAMES,
+ SystemPropertiesProto::Ro::Build::_FIELD_IDS,
+ SystemPropertiesProto::Ro::Build::_FIELD_COUNT);
+ Message build(&buildTable);
+
+ Table versionTable(SystemPropertiesProto::Ro::Build::Version::_FIELD_NAMES,
+ SystemPropertiesProto::Ro::Build::Version::_FIELD_IDS,
+ SystemPropertiesProto::Ro::Build::Version::_FIELD_COUNT);
+ Message version(&versionTable);
+ build.addSubMessage(SystemPropertiesProto::Ro::Build::VERSION, &version);
+ ro.addSubMessage(SystemPropertiesProto::Ro::BUILD, &build);
+
+ Table configTable(SystemPropertiesProto::Ro::Config::_FIELD_NAMES,
+ SystemPropertiesProto::Ro::Config::_FIELD_IDS,
+ SystemPropertiesProto::Ro::Config::_FIELD_COUNT);
+ Message config(&configTable);
+ ro.addSubMessage(SystemPropertiesProto::Ro::CONFIG, &config);
+
+ Table hardwareTable(SystemPropertiesProto::Ro::Hardware::_FIELD_NAMES,
+ SystemPropertiesProto::Ro::Hardware::_FIELD_IDS,
+ SystemPropertiesProto::Ro::Hardware::_FIELD_COUNT);
+ Message hardware(&hardwareTable);
+ ro.addSubMessage(SystemPropertiesProto::Ro::HARDWARE, &hardware);
+
+ Table productTable(SystemPropertiesProto::Ro::Product::_FIELD_NAMES,
+ SystemPropertiesProto::Ro::Product::_FIELD_IDS,
+ SystemPropertiesProto::Ro::Product::_FIELD_COUNT);
+ Message product(&productTable);
+
+ Table vendorTable(SystemPropertiesProto::Ro::Product::Vendor::_FIELD_NAMES,
+ SystemPropertiesProto::Ro::Product::Vendor::_FIELD_IDS,
+ SystemPropertiesProto::Ro::Product::Vendor::_FIELD_COUNT);
+ Message vendor(&vendorTable);
+ product.addSubMessage(SystemPropertiesProto::Ro::Product::VENDOR, &vendor);
+ ro.addSubMessage(SystemPropertiesProto::Ro::PRODUCT, &product);
+ sysProp.addSubMessage(SystemPropertiesProto::RO, &ro);
+
+ Table sysTable(SystemPropertiesProto::Sys::_FIELD_NAMES,
+ SystemPropertiesProto::Sys::_FIELD_IDS,
+ SystemPropertiesProto::Sys::_FIELD_COUNT);
+ Message sys(&sysTable);
+
+ Table usbTable(SystemPropertiesProto::Sys::Usb::_FIELD_NAMES,
+ SystemPropertiesProto::Sys::Usb::_FIELD_IDS,
+ SystemPropertiesProto::Sys::Usb::_FIELD_COUNT);
+ Message usb(&usbTable);
+ sys.addSubMessage(SystemPropertiesProto::Sys::USB, &usb);
+
+ sysProp.addSubMessage(SystemPropertiesProto::SYS, &sys);
// parse line by line
while (reader.readLine(&line)) {
@@ -67,13 +186,19 @@
// if the property name couldn't be found in proto definition or the value has mistype,
// add to extra properties with its name and value
- if (!table.insertField(&proto, convertToFieldName(name), value)) {
- long long token = proto.start(SystemPropertiesProto::EXTRA_PROPERTIES);
- proto.write(SystemPropertiesProto::Property::NAME, name);
- proto.write(SystemPropertiesProto::Property::VALUE, value);
- proto.end(token);
+ if (!sysProp.insertField(&proto, convertToFieldName(name), value)) {
+ extras.push_back(make_pair(name, value));
}
}
+ // end session for the last write.
+ sysProp.endSession(&proto);
+
+ for (auto it = extras.begin(); it != extras.end(); it++) {
+ long long token = proto.start(SystemPropertiesProto::EXTRA_PROPERTIES);
+ proto.write(SystemPropertiesProto::Property::NAME, it->first);
+ proto.write(SystemPropertiesProto::Property::VALUE, it->second);
+ proto.end(token);
+ }
if (!reader.ok(&line)) {
fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
diff --git a/cmds/incident_helper/testdata/system_properties.txt b/cmds/incident_helper/testdata/system_properties.txt
index 57c07ee..bf7d4ad 100644
--- a/cmds/incident_helper/testdata/system_properties.txt
+++ b/cmds/incident_helper/testdata/system_properties.txt
@@ -1,14 +1,16 @@
+[aac_drc_cut]: [123]
[aaudio.hw_burst_min_usec]: [2000]
[aaudio.mmap_exclusive_policy]: [2]
[dalvik.vm.appimageformat]: [lz4]
-[gsm.operator.isroaming]: [false]
-[init.svc.vendor.imsqmidaemon]: [running]
-[init.svc.vendor.init-radio-sh]: [stopped]
-[net.dns1]: [2001:4860:4860::8844]
-[net.tcp.buffersize.wifi]: [524288,2097152,4194304,262144,524288,1048576]
-[nfc.initialized]: [True]
-[persist_radio_VT_ENABLE]: [1]
+[drm_64bit_enabled]: [false]
+[init.svc.adbd]: [running]
+[init.svc.lmkd]: [stopped]
+[media_mediadrmservice_enable]: [True]
[ro.boot.boottime]: [1BLL:85,1BLE:898,2BLL:0,2BLE:862,SW:6739,KL:340]
[ro.bootimage.build.date.utc]: [1509394807]
[ro.bootimage.build.fingerprint]: [google/marlin/marlin:P/MASTER/jinyithu10301320:eng/dev-keys]
-[ro.wifi.channels]: []
\ No newline at end of file
+[ro.hardware]: [marlin]
+[ro.hardware.power]: [marlin-profile]
+[ro.product.cpu.abilist]: [arm64-v8a,armeabi-v7a,armeabi]
+[ro.product.vendor.brand]: [google]
+[ro.wifi.channels]: []
diff --git a/cmds/incident_helper/tests/CpuFreqParser_test.cpp b/cmds/incident_helper/tests/CpuFreqParser_test.cpp
index 1c2f9e5..82deee4 100644
--- a/cmds/incident_helper/tests/CpuFreqParser_test.cpp
+++ b/cmds/incident_helper/tests/CpuFreqParser_test.cpp
@@ -21,7 +21,7 @@
#include <android-base/file.h>
#include <android-base/test_utils.h>
#include <gmock/gmock.h>
-#include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
#include <gtest/gtest.h>
#include <string.h>
#include <fcntl.h>
@@ -42,13 +42,6 @@
ASSERT_TRUE(tf.fd != -1);
}
- string getSerializedString(::google::protobuf::Message& message) {
- string expectedStr;
- message.SerializeToFileDescriptor(tf.fd);
- ReadFileToString(tf.path, &expectedStr);
- return expectedStr;
- }
-
protected:
TemporaryFile tf;
@@ -125,6 +118,6 @@
CaptureStdout();
ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
- EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
+ EXPECT_EQ(GetCapturedStdout(), expected.SerializeAsString());
close(fd);
}
diff --git a/cmds/incident_helper/tests/CpuInfoParser_test.cpp b/cmds/incident_helper/tests/CpuInfoParser_test.cpp
index bbc14bc..8dce53e 100644
--- a/cmds/incident_helper/tests/CpuInfoParser_test.cpp
+++ b/cmds/incident_helper/tests/CpuInfoParser_test.cpp
@@ -21,7 +21,7 @@
#include <android-base/file.h>
#include <android-base/test_utils.h>
#include <gmock/gmock.h>
-#include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
#include <gtest/gtest.h>
#include <string.h>
#include <fcntl.h>
@@ -42,13 +42,6 @@
ASSERT_TRUE(tf.fd != -1);
}
- string getSerializedString(::google::protobuf::Message& message) {
- string expectedStr;
- message.SerializeToFileDescriptor(tf.fd);
- ReadFileToString(tf.path, &expectedStr);
- return expectedStr;
- }
-
protected:
TemporaryFile tf;
@@ -153,6 +146,6 @@
CaptureStdout();
ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
- EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
+ EXPECT_EQ(GetCapturedStdout(), expected.SerializeAsString());
close(fd);
}
diff --git a/cmds/incident_helper/tests/KernelWakesParser_test.cpp b/cmds/incident_helper/tests/KernelWakesParser_test.cpp
index a8fa6208..a98c62b 100644
--- a/cmds/incident_helper/tests/KernelWakesParser_test.cpp
+++ b/cmds/incident_helper/tests/KernelWakesParser_test.cpp
@@ -21,7 +21,7 @@
#include <android-base/file.h>
#include <android-base/test_utils.h>
#include <gmock/gmock.h>
-#include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
#include <gtest/gtest.h>
#include <string.h>
#include <fcntl.h>
@@ -42,13 +42,6 @@
ASSERT_TRUE(tf.fd != -1);
}
- string getSerializedString(::google::protobuf::Message& message) {
- string expectedStr;
- message.SerializeToFileDescriptor(tf.fd);
- ReadFileToString(tf.path, &expectedStr);
- return expectedStr;
- }
-
protected:
TemporaryFile tf;
@@ -76,7 +69,7 @@
CaptureStdout();
ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
- EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
+ EXPECT_EQ(GetCapturedStdout(), expected.SerializeAsString());
close(fd);
}
@@ -114,6 +107,6 @@
CaptureStdout();
ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
- EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
+ EXPECT_EQ(GetCapturedStdout(), expected.SerializeAsString());
close(fd);
}
diff --git a/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp b/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp
index de64e70..a9e6e816 100644
--- a/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp
+++ b/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp
@@ -21,7 +21,7 @@
#include <android-base/file.h>
#include <android-base/test_utils.h>
#include <gmock/gmock.h>
-#include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
#include <gtest/gtest.h>
#include <string.h>
#include <fcntl.h>
@@ -42,13 +42,6 @@
ASSERT_TRUE(tf.fd != -1);
}
- string getSerializedString(::google::protobuf::Message& message) {
- string expectedStr;
- message.SerializeToFileDescriptor(tf.fd);
- ReadFileToString(tf.path, &expectedStr);
- return expectedStr;
- }
-
protected:
TemporaryFile tf;
@@ -108,6 +101,6 @@
CaptureStdout();
ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
- EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
+ EXPECT_EQ(GetCapturedStdout(), expected.SerializeAsString());
close(fd);
-}
\ No newline at end of file
+}
diff --git a/cmds/incident_helper/tests/ProcrankParser_test.cpp b/cmds/incident_helper/tests/ProcrankParser_test.cpp
index e86647a..76b25d7 100644
--- a/cmds/incident_helper/tests/ProcrankParser_test.cpp
+++ b/cmds/incident_helper/tests/ProcrankParser_test.cpp
@@ -21,7 +21,7 @@
#include <android-base/file.h>
#include <android-base/test_utils.h>
#include <gmock/gmock.h>
-#include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
#include <gtest/gtest.h>
#include <string.h>
#include <fcntl.h>
@@ -42,13 +42,6 @@
ASSERT_TRUE(tf.fd != -1);
}
- string getSerializedString(::google::protobuf::Message& message) {
- string expectedStr;
- message.SerializeToFileDescriptor(tf.fd);
- ReadFileToString(tf.path, &expectedStr);
- return expectedStr;
- }
-
protected:
TemporaryFile tf;
@@ -104,7 +97,7 @@
CaptureStdout();
ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
- EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
+ EXPECT_EQ(GetCapturedStdout(), expected.SerializeAsString());
close(fd);
}
@@ -142,6 +135,6 @@
CaptureStdout();
ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
- EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
+ EXPECT_EQ(GetCapturedStdout(), expected.SerializeAsString());
close(fd);
}
diff --git a/cmds/incident_helper/tests/SystemPropertiesParser_test.cpp b/cmds/incident_helper/tests/SystemPropertiesParser_test.cpp
index 23e292a..ef28c51 100644
--- a/cmds/incident_helper/tests/SystemPropertiesParser_test.cpp
+++ b/cmds/incident_helper/tests/SystemPropertiesParser_test.cpp
@@ -21,7 +21,7 @@
#include <android-base/file.h>
#include <android-base/test_utils.h>
#include <gmock/gmock.h>
-#include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
#include <gtest/gtest.h>
#include <string.h>
#include <fcntl.h>
@@ -42,13 +42,6 @@
ASSERT_TRUE(tf.fd != -1);
}
- string getSerializedString(::google::protobuf::Message& message) {
- string expectedStr;
- message.SerializeToFileDescriptor(tf.fd);
- ReadFileToString(tf.path, &expectedStr);
- return expectedStr;
- }
-
protected:
TemporaryFile tf;
@@ -61,35 +54,39 @@
SystemPropertiesParser parser;
SystemPropertiesProto expected;
- expected.set_aaudio_hw_burst_min_usec(2000);
- expected.set_aaudio_mmap_exclusive_policy(2);
- expected.set_dalvik_vm_appimageformat("lz4");
- expected.set_gsm_operator_isroaming(false);
- expected.set_init_svc_vendor_imsqmidaemon(SystemPropertiesProto_Status_STATUS_RUNNING);
- expected.set_init_svc_vendor_init_radio_sh(SystemPropertiesProto_Status_STATUS_STOPPED);
- expected.set_net_dns1("2001:4860:4860::8844");
- expected.add_net_tcp_buffersize_wifi(524288);
- expected.add_net_tcp_buffersize_wifi(2097152);
- expected.add_net_tcp_buffersize_wifi(4194304);
- expected.add_net_tcp_buffersize_wifi(262144);
- expected.add_net_tcp_buffersize_wifi(524288);
- expected.add_net_tcp_buffersize_wifi(1048576);
- expected.set_nfc_initialized(true);
- expected.set_persist_radio_vt_enable(1);
- expected.add_ro_boot_boottime("1BLL:85");
- expected.add_ro_boot_boottime("1BLE:898");
- expected.add_ro_boot_boottime("2BLL:0");
- expected.add_ro_boot_boottime("2BLE:862");
- expected.add_ro_boot_boottime("SW:6739");
- expected.add_ro_boot_boottime("KL:340");
- expected.set_ro_bootimage_build_date_utc(1509394807LL);
- expected.set_ro_bootimage_build_fingerprint("google/marlin/marlin:P/MASTER/jinyithu10301320:eng/dev-keys");
+ expected.mutable_aac_drc()->set_cut(123);
+ expected.mutable_aaudio()->set_hw_burst_min_usec(2000);
+ expected.mutable_aaudio()->set_mmap_exclusive_policy(2);
+ expected.mutable_dalvik_vm()->set_appimageformat("lz4");
+ expected.set_drm_64bit_enabled(false);
+ expected.mutable_init_svc()->set_adbd(
+ SystemPropertiesProto_InitSvc_Status_STATUS_RUNNING);
+ expected.mutable_init_svc()->set_lmkd(
+ SystemPropertiesProto_InitSvc_Status_STATUS_STOPPED);
+ expected.set_media_mediadrmservice_enable(true);
+
+ SystemPropertiesProto::Ro* ro = expected.mutable_ro();
+ ro->mutable_boot()->add_boottime("1BLL:85");
+ ro->mutable_boot()->add_boottime("1BLE:898");
+ ro->mutable_boot()->add_boottime("2BLL:0");
+ ro->mutable_boot()->add_boottime("2BLE:862");
+ ro->mutable_boot()->add_boottime("SW:6739");
+ ro->mutable_boot()->add_boottime("KL:340");
+ ro->mutable_bootimage()->set_build_date_utc(1509394807LL);
+ ro->mutable_bootimage()->set_build_fingerprint(
+ "google/marlin/marlin:P/MASTER/jinyithu10301320:eng/dev-keys");
+ ro->mutable_hardware()->set_value("marlin");
+ ro->mutable_hardware()->set_power("marlin-profile");
+ ro->mutable_product()->add_cpu_abilist("arm64-v8a");
+ ro->mutable_product()->add_cpu_abilist("armeabi-v7a");
+ ro->mutable_product()->add_cpu_abilist("armeabi");
+ ro->mutable_product()->mutable_vendor()->set_brand("google");
int fd = open(testFile.c_str(), O_RDONLY);
ASSERT_TRUE(fd != -1);
CaptureStdout();
ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
- EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
+ EXPECT_EQ(GetCapturedStdout(), expected.SerializeAsString());
close(fd);
}
diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk
index cb5fd02..fb8ef63 100644
--- a/cmds/incidentd/Android.mk
+++ b/cmds/incidentd/Android.mk
@@ -120,14 +120,6 @@
libservices \
libutils \
-relative_path_prefix := nativetest64/incidentd_test
-testdata_files := $(call find-subdir-files, testdata/*)
-
-GEN := $(addprefix $(TARGET_OUT_DATA)/$(relative_path_prefix)/, $(testdata_files))
-$(GEN): PRIVATE_PATH := $(LOCAL_PATH)
-$(GEN): PRIVATE_CUSTOM_TOOL = cp $< $@
-$(GEN): $(TARGET_OUT_DATA)/$(relative_path_prefix)/testdata/% : $(LOCAL_PATH)/testdata/%
- $(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
+LOCAL_TEST_DATA := $(call find-test-data-in-subdirs, $(LOCAL_PATH), *, testdata)
include $(BUILD_NATIVE_TEST)
diff --git a/cmds/incidentd/AndroidTest.xml b/cmds/incidentd/AndroidTest.xml
new file mode 100644
index 0000000..7f0e4ee
--- /dev/null
+++ b/cmds/incidentd/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?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="Config for incidentd_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="incidentd_test->/data/nativetest/incidentd_test" />
+ <option name="push" value="testdata->/data/nativetest/testdata" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/nativetest" />
+ <option name="module-name" value="incidentd_test" />
+ </test>
+</configuration>
diff --git a/cmds/incidentd/README.md b/cmds/incidentd/README.md
index daa3924..ad0fa08 100644
--- a/cmds/incidentd/README.md
+++ b/cmds/incidentd/README.md
@@ -5,13 +5,19 @@
For the first time, build the test and create an empty directly on device:
```
-root$ make -j incidentd_test && adb shell mkdir /data/nativetest64/incidentd_test
+root$ make -j incidentd_test && adb shell mkdir /data/nativetest/incidentd_test
```
-Run the test on a device
+Run the test on a device manually
```
root$ mmm -j frameworks/base/cmds/incidentd && \
-adb push $OUT/data/nativetest64/incidentd_test/* /data/nativetest64/incidentd_test/ && \
-adb shell /data/nativetest64/incidentd_test/incidentd_test 2>/dev/null
+adb push $OUT/data/nativetest/incidentd_test/* /data/nativetest/incidentd_test/ && \
+adb shell /data/nativetest/incidentd_test/incidentd_test 2>/dev/null
```
+
+Run the test via AndroidTest.xml
+
+```
+root$ atest incidentd_test
+```
\ No newline at end of file
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/statsd/Android.bp b/cmds/statsd/Android.bp
index 5fcb8a1..a5eae15 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -31,5 +31,11 @@
type: "full",
export_proto_headers: true,
},
+
+ export_shared_lib_headers: [
+ "libplatformprotos",
+ ]
+
}
+
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 1f15c5e..addba8c 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -19,7 +19,7 @@
../../core/java/android/os/IStatsManager.aidl \
src/stats_log.proto \
src/statsd_config.proto \
- src/atoms_copy.proto \
+ src/atoms.proto \
src/anomaly/AnomalyMonitor.cpp \
src/anomaly/AnomalyTracker.cpp \
src/condition/CombinationConditionTracker.cpp \
@@ -51,8 +51,6 @@
src/metrics/MetricsManager.cpp \
src/metrics/metrics_manager_util.cpp \
src/packages/UidMap.cpp \
- src/storage/DropboxReader.cpp \
- src/storage/DropboxWriter.cpp \
src/storage/StorageManager.cpp \
src/StatsLogProcessor.cpp \
src/StatsService.cpp \
@@ -67,6 +65,9 @@
statsd_common_aidl_includes := \
$(LOCAL_PATH)/../../core/java
+statsd_common_static_libraries := \
+ libplatformprotos
+
statsd_common_shared_libraries := \
libbase \
libbinder \
@@ -76,7 +77,6 @@
libselinux \
libutils \
libservices \
- libandroidfw \
libprotoutil \
libstatslog \
libhardware \
@@ -121,12 +121,14 @@
LOCAL_AIDL_INCLUDES := $(statsd_common_aidl_includes)
LOCAL_C_INCLUDES += $(statsd_common_c_includes)
+LOCAL_STATIC_LIBRARIES := $(statsd_common_static_libraries)
+
LOCAL_SHARED_LIBRARIES := $(statsd_common_shared_libraries) \
libgtest_prod
LOCAL_MODULE_CLASS := EXECUTABLES
-#LOCAL_INIT_RC := statsd.rc
+LOCAL_INIT_RC := statsd.rc
include $(BUILD_EXECUTABLE)
@@ -161,28 +163,35 @@
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
LOCAL_STATIC_LIBRARIES := \
+ $(statsd_common_static_libraries) \
libgmock
LOCAL_SHARED_LIBRARIES := $(statsd_common_shared_libraries)
LOCAL_PROTOC_OPTIMIZE_TYPE := lite
+include $(BUILD_NATIVE_TEST)
+
+
statsd_common_src:=
statsd_common_aidl_includes:=
statsd_common_c_includes:=
+statsd_common_static_libraries:=
+statsd_common_shared_libraries:=
-include $(BUILD_NATIVE_TEST)
##############################
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 57b4fc1..a3e39b6 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -58,7 +58,7 @@
const int FIELD_ID_METRICS = 1;
const int FIELD_ID_UID_MAP = 2;
-#define STATS_DATA_DIR "/data/system/stats-data"
+#define STATS_DATA_DIR "/data/misc/stats-data"
StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap,
const sp<AnomalyMonitor>& anomalyMonitor,
@@ -86,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.
@@ -111,9 +111,7 @@
unique_ptr<MetricsManager> newMetricsManager = std::make_unique<MetricsManager>(key, config);
auto it = mMetricsManagers.find(key);
- if (it != mMetricsManagers.end()) {
- it->second->finish();
- } else if (mMetricsManagers.size() > StatsdStats::kMaxConfigCount) {
+ if (it == mMetricsManagers.end() && mMetricsManagers.size() > StatsdStats::kMaxConfigCount) {
ALOGE("Can't accept more configs!");
return;
}
@@ -167,11 +165,7 @@
// First, fill in ConfigMetricsReport using current data on memory, which
// starts from filling in StatsLogReport's.
- for (auto& m : it->second->onDumpReport()) {
- // Add each vector of StatsLogReport into a repeated field.
- proto.write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS,
- reinterpret_cast<char*>(m.get()->data()), m.get()->size());
- }
+ it->second->onDumpReport(&proto);
// Fill in UidMap.
auto uidMap = mUidMap->getOutput(key);
@@ -205,7 +199,6 @@
void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
auto it = mMetricsManagers.find(key);
if (it != mMetricsManagers.end()) {
- it->second->finish();
mMetricsManagers.erase(it);
mUidMap->OnConfigRemoved(key);
}
@@ -215,16 +208,33 @@
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.
+ // TODO(b/70571383): By 12/15/2017 add API to drop data directly
+ ProtoOutputStream proto;
+ metricsManager.onDumpReport(&proto);
+ 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;
}
}
@@ -232,11 +242,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().noteDataDropped(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 27e3854..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);
@@ -60,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 c019d5d..4dd2539 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -23,7 +23,6 @@
#include "config/ConfigManager.h"
#include "guardrail/MemoryLeakTrackUtil.h"
#include "guardrail/StatsdStats.h"
-#include "storage/DropboxReader.h"
#include "storage/StorageManager.h"
#include <android-base/file.h>
@@ -46,7 +45,7 @@
namespace statsd {
constexpr const char* kPermissionDump = "android.permission.DUMP";
-#define STATS_SERVICE_DIR "/data/system/stats-service"
+#define STATS_SERVICE_DIR "/data/misc/stats-service"
// ======================================================================
/**
@@ -72,7 +71,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();
@@ -201,11 +200,6 @@
return cmd_config(in, out, err, args);
}
- // adb shell cmd stats print-stats-log
- if (!args[0].compare(String8("print-stats-log")) && args.size() > 1) {
- return cmd_print_stats_log(out, args);
- }
-
if (!args[0].compare(String8("print-uid-map"))) {
return cmd_print_uid_map(out);
}
@@ -284,12 +278,13 @@
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");
@@ -427,10 +422,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();
@@ -460,8 +460,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.
@@ -480,7 +486,7 @@
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) {
@@ -491,15 +497,6 @@
return NO_ERROR;
}
-status_t StatsService::cmd_print_stats_log(FILE* out, const Vector<String8>& args) {
- long msec = 0;
-
- if (args.size() > 2) {
- msec = strtol(args[2].string(), NULL, 10);
- }
- return DropboxReader::readStatsLogs(out, args[1].string(), msec);
-}
-
status_t StatsService::cmd_print_uid_map(FILE* out) {
mUidMap->printUidMap(out);
return NO_ERROR;
@@ -539,7 +536,7 @@
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) {
VLOG("StatsService::informAllUidData was called");
@@ -554,7 +551,7 @@
return Status::ok();
}
-Status StatsService::informOnePackage(const String16& app, int32_t uid, int32_t version) {
+Status StatsService::informOnePackage(const String16& app, int32_t uid, int64_t version) {
VLOG("StatsService::informOnePackage was called");
if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
@@ -703,6 +700,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,
@@ -719,6 +728,7 @@
*success = true;
return Status::ok();
} else {
+ *success = false;
return Status::fromExceptionCode(binder::Status::EX_SECURITY);
}
}
@@ -728,6 +738,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 007227e..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.
*/
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
index 2b2bcfc..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 {
@@ -76,10 +77,7 @@
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;
@@ -106,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);
@@ -123,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();
}
}
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.h b/cmds/statsd/src/anomaly/AnomalyMonitor.h
index e19c469..7acc7904 100644
--- a/cmds/statsd/src/anomaly/AnomalyMonitor.h
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.h
@@ -138,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 7bacb44..e8b4083 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -18,6 +18,7 @@
#include "Log.h"
#include "AnomalyTracker.h"
+#include "guardrail/StatsdStats.h"
#include <android/os/IIncidentManager.h>
#include <android/os/IncidentReportArgs.h>
@@ -31,8 +32,9 @@
// 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)
+AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey)
: mAlert(alert),
+ mConfigKey(configKey),
mNumOfPastBuckets(mAlert.number_of_buckets() - 1) {
VLOG("AnomalyTracker() called");
if (mAlert.number_of_buckets() <= 0) {
@@ -220,6 +222,8 @@
} else {
ALOGW("An anomaly has occurred! (But informing incidentd not requested.)");
}
+
+ StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.name());
}
void AnomalyTracker::declareAnomalyIfAlarmExpired(const HashableDimensionKey& dimensionKey,
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index 49e8323..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
@@ -35,7 +36,7 @@
// Does NOT allow negative values.
class AnomalyTracker : public virtual RefBase {
public:
- AnomalyTracker(const Alert& alert);
+ AnomalyTracker(const Alert& alert, const ConfigKey& configKey);
virtual ~AnomalyTracker();
@@ -107,9 +108,13 @@
protected:
void flushPastBuckets(const int64_t& currBucketNum);
+
// statsd_config.proto Alert message that defines this tracker.
const Alert mAlert;
+ // A reference to the Alert's config key.
+ const ConfigKey& mConfigKey;
+
// 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;
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 20e7c60..716fee6 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -21,6 +21,8 @@
option java_package = "com.android.os";
option java_outer_classname = "AtomsProto";
+import "frameworks/base/core/proto/android/app/activitymanager.proto";
+
/**
* The master atom class. This message defines all of the available
* raw stats log events from the Android system, also known as "atoms."
@@ -46,12 +48,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 +95,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 +105,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 +153,7 @@
STATE_DOZE = 3;
STATE_DOZE_SUSPEND = 4;
STATE_VR = 5;
+ STATE_ON_SUSPEND = 6;
}
// New screen state.
optional State display_state = 1;
@@ -159,7 +170,7 @@
// The state.
// TODO: Use the real (mapped) process states.
- optional int32 state = 2;
+ optional android.app.ProcessState state = 2;
}
/**
@@ -175,13 +186,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 +419,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 +468,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 +594,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 +756,7 @@
optional int32 user = 7;
}
-/*
+/**
* Logs activity going to foreground or background
*
* Logged from:
@@ -839,7 +896,7 @@
optional int64 time = 4;
}
-/*
+/**
* Pulls PowerStatePlatformSleepState.
*
* Definition here:
@@ -899,7 +956,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 +973,7 @@
optional uint64 time = 3;
}
-/*
+/**
* Pulls Cpu Time Per Uid.
* Note that isolated process uid time should be attributed to host uids.
*/
@@ -965,3 +1022,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;
+}
diff --git a/cmds/statsd/src/atoms_copy.proto b/cmds/statsd/src/atoms_copy.proto
deleted file mode 100644
index 58e225a..0000000
--- a/cmds/statsd/src/atoms_copy.proto
+++ /dev/null
@@ -1,910 +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.
- */
-
-syntax = "proto2";
-option optimize_for = LITE_RUNTIME;
-
-
-// TODO: Not the right package and class name
-package android.os.statsd;
-option java_package = "com.android.os";
-option java_outer_classname = "AtomsProto";
-
-/**
- * The master atom class. This message defines all of the available
- * raw stats log events from the Android system, also known as "atoms."
- *
- * This field contains a single oneof with all of the available messages.
- * The stats-log-api-gen tool runs as part of the Android build and
- * generates the android.util.StatsLog class, which contains the constants
- * and methods that Android uses to log.
- *
- * This Atom class is not actually built into the Android system.
- * Instead, statsd on Android constructs these messages synthetically,
- * in the format defined here and in stats_log.proto.
- */
-message Atom {
- // Pushed atoms start at 2.
- oneof pushed {
- // For StatsLog reasons, 1 is illegal and will not work. Must start at 2.
- BleScanStateChanged ble_scan_state_changed = 2;
- BleUnoptimizedScanStateChanged ble_unoptimized_scan_state_changed = 3;
- BleScanResultReceived ble_scan_result_received = 4;
- SensorStateChanged sensor_state_changed = 5;
- GpsScanStateChanged gps_scan_state_changed = 6; // TODO: untested
- 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;
- AudioStateChanged audio_state_changed = 23;
- MediaCodecActivityChanged media_codec_activity_changed = 24;
- CameraStateChanged camera_state_changed = 25;
- FlashlightStateChanged flashlight_state_changed = 26;
- UidProcessStateChanged uid_process_state_changed = 27;
- ProcessLifeCycleStateChanged process_life_cycle_state_changed = 28;
- ScreenStateChanged screen_state_changed = 29;
- BatteryLevelChanged battery_level_changed = 30;
- ChargingStateChanged charging_state_changed = 31;
- PluggedStateChanged plugged_state_changed = 32;
- DeviceTemperatureReported device_temperature_reported = 33;
- DeviceOnStatusChanged device_on_status_changed = 34;
- WakeupAlarmOccurred wakeup_alarm_occurred = 35;
- KernelWakeupReported kernel_wakeup_reported = 36;
- WifiLockStateChanged wifi_lock_state_changed = 37;
- WifiSignalStrengthChanged wifi_signal_strength_changed = 38;
- WifiScanStateChanged wifi_scan_state_changed = 39;
- PhoneSignalStrengthChanged phone_signal_strength_changed = 40;
- SettingChanged setting_changed = 41;
- ActivityForegroundStateChanged activity_foreground_state_changed = 42;
- IsolatedUidChanged isolated_uid_changed = 43;
- // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
- }
-
- // Pulled events will start at field 1000.
- oneof pulled {
- WifiBytesTransferred wifi_bytes_transferred = 1000;
- WifiBytesTransferredByFgBg wifi_bytes_transferred_by_fg_bg = 1001;
- MobileBytesTransferred mobile_bytes_transferred = 1002;
- MobileBytesTransferredByFgBg mobile_bytes_transferred_by_fg_bg = 1003;
- KernelWakelockPulled kernel_wakelock_pulled = 1004;
- PowerStatePlatformSleepStatePulled power_state_platform_sleep_state_pulled = 1005;
- PowerStateVoterPulled power_state_voter_pulled = 1006;
- PowerStateSubsystemSleepStatePulled power_state_subsystem_sleep_state_pulled = 1007;
- CpuTimePerFreqPulled cpu_time_per_freq_pulled = 1008;
- CpuTimePerUidPulled cpu_time_per_uid_pulled = 1009;
- CpuTimePerUidFreqPulled cpu_time_per_uid_freq_pulled = 1010;
- }
-}
-
-/**
- * A WorkSource represents the chained attribution of applications that
- * resulted in a particular bit of work being done.
- */
-message WorkSource {
- // TODO
-}
-
-/*
- * *****************************************************************************
- * Below are all of the individual atoms that are logged by Android via statsd.
- *
- * RULES:
- * - The field ids for each atom must start at 1, and count upwards by 1.
- * Skipping field ids is not allowed.
- * - These form an API, so renaming, renumbering or removing fields is
- * not allowed between android releases. (This is not currently enforced,
- * but there will be a tool to enforce this restriction).
- * - The types must be built-in protocol buffer types, namely, no sub-messages
- * are allowed (yet). The bytes type is also not allowed.
- * - The CamelCase name of the message type should match the
- * underscore_separated name as defined in Atom.
- * - If an atom represents work that can be attributed to an app, there can
- * be exactly one WorkSource field. It must be field number 1.
- * - A field that is a uid should be a string field, tagged with the [xxx]
- * annotation. The generated code on android will be represented by UIDs,
- * and those UIDs will be translated in xxx to those strings.
- *
- * CONVENTIONS:
- * - Events are past tense. e.g. ScreenStateChanged, not ScreenStateChange.
- * - If there is a UID, it goes first. Think in an object-oriented fashion.
- * *****************************************************************************
- */
-
-/**
- * Logs when the screen state changes.
- *
- * Logged from:
- * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message ScreenStateChanged {
- // TODO: Use the real screen state.
- enum State {
- STATE_UNKNOWN = 0;
- STATE_OFF = 1;
- STATE_ON = 2;
- STATE_DOZE = 3;
- STATE_DOZE_SUSPEND = 4;
- STATE_VR = 5;
- }
- // New screen state.
- optional State display_state = 1;
-}
-
-/**
- * Logs that the state of a process state, as per the activity manager, has changed.
- *
- * Logged from:
- * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message UidProcessStateChanged {
- optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation
-
- // The state.
- // TODO: Use the real (mapped) process states.
- optional int32 state = 2;
-}
-
-/**
- * Logs that a process started, finished, crashed, or ANRed.
- *
- * Logged from:
- * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message ProcessLifeCycleStateChanged {
- // TODO: Use the real (mapped) process states.
- optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation
-
- // TODO: What is this?
- optional string name = 2;
-
- // The state.
- // TODO: Use an enum.
- optional int32 event = 3;
-}
-
-
-
-/**
- * Logs when the ble scan state changes.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message BleScanStateChanged {
- // TODO: Add attribution instead of uid.
- optional int32 uid = 1;
-
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 2;
-}
-
-/**
- * Logs when an unoptimized ble scan state changes.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-// TODO: Consider changing to tracking per-scanner-id (log from AppScanStats).
-message BleUnoptimizedScanStateChanged {
- // TODO: Add attribution instead of uid.
- optional int32 uid = 1;
-
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 2;
-}
-
-/**
- * Logs reporting of a ble scan finding results.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-// TODO: Consider changing to tracking per-scanner-id (log from AppScanStats).
-message BleScanResultReceived {
- // TODO: Add attribution instead of uid.
- optional int32 uid = 1;
-
- // Number of ble scan results returned.
- optional int32 num_of_results = 2;
-}
-
-/**
- * Logs when a sensor state changes.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message SensorStateChanged {
- // TODO: Add attribution instead of uid.
- optional int32 uid = 1;
-
- // TODO: Is there a way to get the actual name of the sensor?
- // The id (int) of the sensor.
- optional int32 sensor_id = 2;
-
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 3;
-}
-
-
-/**
- * Logs when GPS state changes.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message GpsScanStateChanged {
- // TODO: Add attribution instead of uid.
- optional int32 uid = 1;
-
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 2;
-}
-
-
-/**
- * Logs when a sync manager sync state changes.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message SyncStateChanged {
- // TODO: Add attribution instead of uid.
- optional int32 uid = 1;
-
- // Name of the sync (as named in the app)
- optional string name = 2;
-
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 3;
-}
-
-/**
- * Logs when a job scheduler job state changes.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message ScheduledJobStateChanged {
- // TODO: Add attribution instead of uid.
- optional int32 uid = 1;
-
- // Name of the job (as named in the app)
- optional string name = 2;
-
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 3;
-
- // TODO: Consider adding the stopReason (int)
-}
-
-/**
- * Logs when the audio state changes.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message AudioStateChanged {
- // TODO: Add attribution instead of uid.
- optional int32 uid = 1;
-
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 2;
-}
-
-/**
- * Logs when the video codec state changes.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message MediaCodecActivityChanged {
- // TODO: Add attribution instead of uid.
- optional int32 uid = 1;
-
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 2;
-}
-
-/**
- * Logs when the flashlight state changes.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message FlashlightStateChanged {
- // TODO: Add attribution instead of uid.
- optional int32 uid = 1;
-
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 2;
-}
-
-/**
- * Logs when the camera state changes.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message CameraStateChanged {
- // TODO: Add attribution instead of uid.
- optional int32 uid = 1;
-
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 2;
-}
-
-/**
- * Logs that the state of a wakelock (per app and per wakelock name) has changed.
- *
- * Logged from:
- * TODO
- */
-message WakelockStateChanged {
- // 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;
-
- // The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
- optional string tag = 3;
-
- enum State {
- OFF = 0;
- ON = 1;
- }
- 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:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message LongPartialWakelockStateChanged {
- // TODO: Add attribution instead of uid?
- optional int32 uid = 1;
-
- // The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
- optional string tag = 2;
-
- // TODO: I have no idea what this is.
- optional string history_tag = 3;
-
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 4;
-}
-
-/**
- * Logs Battery Saver state change.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message BatterySaverModeStateChanged {
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 1;
-}
-
-/**
- * Logs Doze mode state change.
- *
- * Logged from:
- * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message DeviceIdleModeStateChanged {
- // TODO: Use the enum matching BatteryStats.DEVICE_IDLE_MODE_.
- optional int32 state = 1;
-}
-
-/**
- * Logs screen brightness level.
- *
- * Logged from:
- * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message ScreenBrightnessChanged {
- // Screen brightness level. Should be in [-1, 255] according to PowerManager.java.
- optional int32 level = 1;
-}
-
-/**
- * Logs battery level (percent full, from 0 to 100).
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message BatteryLevelChanged {
- // Battery level. Should be in [0, 100].
- optional int32 battery_level = 1;
-}
-
-/**
- * Logs change in charging status of the device.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message ChargingStateChanged {
- // TODO: Link directly to BatteryManager.java's constants (via a proto).
- enum State {
- BATTERY_STATUS_UNKNOWN = 1;
- BATTERY_STATUS_CHARGING = 2;
- BATTERY_STATUS_DISCHARGING = 3;
- BATTERY_STATUS_NOT_CHARGING = 4;
- BATTERY_STATUS_FULL = 5;
- }
- optional State charging_state = 1;
-}
-
-/**
- * Logs whether the device is plugged in, and what power source it is using.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message PluggedStateChanged {
- // TODO: Link directly to BatteryManager.java's constants (via a proto).
- enum State {
- // Note that NONE is not in BatteryManager.java's constants.
- BATTERY_PLUGGED_NONE = 0;
- // Power source is an AC charger.
- BATTERY_PLUGGED_AC = 1;
- // Power source is a USB port.
- BATTERY_PLUGGED_USB = 2;
- // Power source is wireless.
- BATTERY_PLUGGED_WIRELESS = 4;
- }
- optional State plugged_state = 1;
-}
-
-/**
- * Logs the temperature of the device, in tenths of a degree Celsius.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message DeviceTemperatureReported {
- // Temperature in tenths of a degree C.
- optional int32 temperature = 1;
-}
-
-// TODO: Define this more precisely.
-// TODO: Log the ON state somewhere. It isn't currently logged anywhere.
-/**
- * Logs when the device turns off or on.
- *
- * Logged from:
- * frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message DeviceOnStatusChanged {
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 1;
-}
-
-/**
- * Logs when an app's wakeup alarm fires.
- *
- * Logged from:
- * frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message WakeupAlarmOccurred {
- // TODO: Add attribution instead of uid?
- optional int32 uid = 1;
-}
-
-/**
- * Logs kernel wakeup reasons and aborts.
- *
- * Logged from:
- * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message KernelWakeupReported {
- // Name of the kernel wakeup reason (or abort).
- optional string wakeup_reason_name = 1;
-
- // Duration (in microseconds) for the wake-up interrupt to be serviced.
- optional int64 duration_usec = 2;
-}
-
-/**
- * Logs wifi locks held by an app.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message WifiLockStateChanged {
- // TODO: Add attribution instead of uid.
- optional int32 uid = 1;
-
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 2;
-}
-
-/**
- * Logs wifi signal strength changes.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message WifiSignalStrengthChanged {
- // TODO: Reference the actual telephony/java/android/telephony/SignalStrength.java states.
- enum SignalStrength {
- SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
- SIGNAL_STRENGTH_POOR = 1;
- SIGNAL_STRENGTH_MODERATE = 2;
- SIGNAL_STRENGTH_GOOD = 3;
- SIGNAL_STRENGTH_GREAT = 4;
- }
- optional SignalStrength signal_strength = 1;
-}
-
-/**
- * Logs wifi scans performed by an app.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message WifiScanStateChanged {
- // TODO: Add attribution instead of uid.
- optional int32 uid = 1;
-
- enum State {
- OFF = 0;
- ON = 1;
- }
- optional State state = 2;
-}
-
-/**
- * Logs phone signal strength changes.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message PhoneSignalStrengthChanged {
- // TODO: Reference the actual telephony/java/android/telephony/SignalStrength.java states.
- enum SignalStrength {
- SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
- SIGNAL_STRENGTH_POOR = 1;
- SIGNAL_STRENGTH_MODERATE = 2;
- SIGNAL_STRENGTH_GOOD = 3;
- SIGNAL_STRENGTH_GREAT = 4;
- }
- optional SignalStrength signal_strength = 1;
-}
-
-/**
- * Logs that a setting was updated.
- * Logged from:
- * frameworks/base/core/java/android/provider/Settings.java
- * The tag and is_default allow resetting of settings to default values based on the specified
- * tag. See Settings#putString(ContentResolver, String, String, String, boolean) for more details.
- */
-message SettingChanged {
- // The name of the setting.
- optional string setting = 1;
-
- // The change being imposed on this setting. May represent a number, eg "3".
- optional string value = 2;
-
- // The new value of this setting. For most settings, this is same as value. For some settings,
- // value is +X or -X where X represents an element in a set. For example, if the previous value
- // is A,B,C and value is -B, then new_value is A,C and prev_value is A,B,C.
- // The +/- feature is currently only used for location_providers_allowed.
- optional string new_value = 3;
-
- // The previous value of this setting.
- optional string prev_value = 4;
-
- // The tag used with the is_default for resetting sets of settings. This is generally null.
- optional string tag = 5;
-
- // 1 indicates that this setting with tag should be resettable.
- optional int32 is_default = 6;
-
- // The user ID associated. Defined in android/os/UserHandle.java
- optional int32 user = 7;
-}
-
-/*
- * Logs activity going to foreground or background
- *
- * Logged from:
- * frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java
- */
-message ActivityForegroundStateChanged {
- enum Activity {
- MOVE_TO_BACKGROUND = 0;
- MOVE_TO_FOREGROUND = 1;
- }
- optional int32 uid = 1;
- optional string pkg_name = 2;
- optional string class_name = 3;
- optional Activity activity = 4;
-}
-
-/**
- * Pulls bytes transferred via wifi (Sum of foreground and background usage).
- *
- * Pulled from:
- * StatsCompanionService (using BatteryStats to get which interfaces are wifi)
- */
-message WifiBytesTransferred {
- optional int32 uid = 1;
-
- optional int64 rx_bytes = 2;
-
- optional int64 rx_packets = 3;
-
- optional int64 tx_bytes = 4;
-
- optional int64 tx_packets = 5;
-}
-
-/**
- * Pulls bytes transferred via wifi (separated by foreground and background usage).
- *
- * Pulled from:
- * StatsCompanionService (using BatteryStats to get which interfaces are wifi)
- */
-message WifiBytesTransferredByFgBg {
- optional int32 uid = 1;
-
- // 1 denotes foreground and 0 denotes background. This is called Set in NetworkStats.
- optional int32 is_foreground = 2;
-
- optional int64 rx_bytes = 3;
-
- optional int64 rx_packets = 4;
-
- optional int64 tx_bytes = 5;
-
- optional int64 tx_packets = 6;
-}
-
-/**
- * Pulls bytes transferred via mobile networks (Sum of foreground and background usage).
- *
- * Pulled from:
- * StatsCompanionService (using BatteryStats to get which interfaces are mobile data)
- */
-message MobileBytesTransferred {
- optional int32 uid = 1;
-
- optional int64 rx_bytes = 2;
-
- optional int64 rx_packets = 3;
-
- optional int64 tx_bytes = 4;
-
- optional int64 tx_packets = 5;
-}
-
-/**
- * Pulls bytes transferred via mobile networks (separated by foreground and background usage).
- *
- * Pulled from:
- * StatsCompanionService (using BatteryStats to get which interfaces are mobile data)
- */
-message MobileBytesTransferredByFgBg {
- optional int32 uid = 1;
-
- // 1 denotes foreground and 0 denotes background. This is called Set in NetworkStats.
- optional int32 is_foreground = 2;
-
- optional int64 rx_bytes = 3;
-
- optional int64 rx_packets = 4;
-
- optional int64 tx_bytes = 5;
-
- optional int64 tx_packets = 6;
-}
-
-/**
- * Pulls the kernel wakelock durations. This atom is adapted from
- * android/internal/os/KernelWakelockStats.java
- *
- * Pulled from:
- * StatsCompanionService using KernelWakelockReader.
- */
-message KernelWakelockPulled {
- optional string name = 1;
-
- optional int32 count = 2;
-
- optional int32 version = 3;
-
- optional int64 time = 4;
-}
-
-/*
- * Pulls PowerStatePlatformSleepState.
- *
- * Definition here:
- * hardware/interfaces/power/1.0/types.hal
- */
-message PowerStatePlatformSleepStatePulled {
- optional string name = 1;
- optional uint64 residency_in_msec_since_boot = 2;
- optional uint64 total_transitions = 3;
- optional bool supported_only_in_suspend = 4;
-}
-
-/**
- * Pulls PowerStateVoter.
- *
- * Definition here:
- * hardware/interfaces/power/1.0/types.hal
- */
-message PowerStateVoterPulled {
- optional string power_state_platform_sleep_state_name = 1;
- optional string power_state_voter_name = 2;
- optional uint64 total_time_in_msec_voted_for_since_boot = 3;
- optional uint64 total_number_of_times_voted_since_boot = 4;
-}
-
-/**
- * Pulls PowerStateSubsystemSleepState.
- *
- * Definition here:
- * hardware/interfaces/power/1.1/types.hal
- */
-message PowerStateSubsystemSleepStatePulled {
- optional string power_state_subsystem_name = 1;
- optional string power_state_subsystem_sleep_state_name = 2;
- optional uint64 residency_in_msec_since_boot = 3;
- optional uint64 total_transitions = 4;
- optional uint64 last_entry_timestamp_ms = 5;
- optional bool supported_only_in_suspend = 6;
-}
-
-/**
- * Logs creation or removal of an isolated uid. Isolated uid's are temporary uid's to sandbox risky
- * behavior in its own uid. However, the metrics of these isolated uid's almost always should be
- * attributed back to the parent (host) uid. One example is Chrome.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message IsolatedUidChanged {
- // The host UID. Generally, we should attribute metrics from the isolated uid to the host uid.
- optional int32 parent_uid = 1;
-
- optional int32 isolated_uid = 2;
-
- // 1 denotes we're creating an isolated uid and 0 denotes removal. We expect an isolated uid to
- // be removed before if it's used for another parent uid.
- 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
- * different metrics.
- * The pulled data is delta of cpu time from last pull, calculated as
- * following:
- * if current time is larger than last value, take delta between the two.
- * if current time is smaller than last value, there must be a cpu
- * hotplug event, and the current time is taken as delta.
- */
-message CpuTimePerFreqPulled {
- optional uint32 cluster = 1;
- optional uint32 freq_index = 2;
- optional uint64 time = 3;
-}
-
-/*
- * Pulls Cpu Time Per Uid.
- * Note that isolated process uid time should be attributed to host uids.
- */
-message CpuTimePerUidPulled {
- optional uint64 uid = 1;
- optional uint64 user_time_ms = 2;
- optional uint64 sys_time_ms = 3;
-}
-
-/**
- * Pulls Cpu Time Per Uid per frequency.
- * Note that isolated process uid time should be attributed to host uids.
- * For each uid, we order the time by descending frequencies.
- */
-message CpuTimePerUidFreqPulled {
- optional uint64 uid = 1;
- optional uint64 freq_idx = 2;
- optional uint64 time_ms = 3;
-}
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 4b7e49a..e52b273 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -29,7 +29,7 @@
namespace os {
namespace statsd {
-#define STATS_SERVICE_DIR "/data/system/stats-service"
+#define STATS_SERVICE_DIR "/data/misc/stats-service"
using android::base::StringPrintf;
using std::unique_ptr;
@@ -214,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;
@@ -272,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
@@ -288,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
@@ -302,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
@@ -314,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.
@@ -324,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);
@@ -348,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/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 2bd3612..bf277f0 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,6 +57,8 @@
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);
@@ -100,11 +101,12 @@
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);
@@ -173,6 +175,27 @@
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) {
lock_guard<std::mutex> lock(mLock);
// if name doesn't exist before, it will create the key with count 0.
@@ -197,6 +220,17 @@
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);
@@ -224,6 +258,8 @@
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();
@@ -232,10 +268,11 @@
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()) {
@@ -267,6 +304,16 @@
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_alerted_times(stats.second);
+ VLOG("alert %s declared %d times", stats.first.c_str(), stats.second);
+ }
+ }
}
void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) {
@@ -336,7 +383,7 @@
}
}
- addSubStatsToConfig(pair.first, configStats);
+ addSubStatsToConfigLocked(pair.first, configStats);
const int numBytes = configStats.ByteSize();
vector<char> buffer(numBytes);
@@ -348,6 +395,7 @@
configStats.clear_matcher_stats();
configStats.clear_condition_stats();
configStats.clear_metric_stats();
+ configStats.clear_alert_stats();
}
VLOG("********Atom stats***********");
@@ -364,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 451144f..4cf168e 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -19,6 +19,7 @@
#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>
@@ -45,6 +46,20 @@
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.
*
@@ -108,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.
@@ -133,6 +173,9 @@
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;
@@ -155,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;
@@ -162,7 +213,8 @@
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);
@@ -176,6 +228,7 @@
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 4338399..fc12013 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -83,8 +83,6 @@
mConditionSliced = true;
}
- startNewProtoOutputStream(mStartTimeNs);
-
VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -93,24 +91,18 @@
VLOG("~CountMetricProducer() called");
}
-void CountMetricProducer::startNewProtoOutputStream(long long startTime) {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
-
- 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);
- mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
-}
-
-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());
}
-void CountMetricProducer::serializeBuckets() {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+void CountMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
+ ProtoOutputStream* protoOutput) {
+ flushIfNeededLocked(dumpTimeNs);
+
+ protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
+ long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
+
VLOG("metric %s dump report now...", mMetric.name().c_str());
for (const auto& counter : mPastBuckets) {
@@ -122,74 +114,57 @@
continue;
}
long long wrapperToken =
- mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
+ protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
// First fill dimension (KeyValuePairs).
for (const auto& kv : it->second) {
- long long dimensionToken =
- mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DIMENSION);
- mProto->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
+ long long dimensionToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DIMENSION);
+ protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
if (kv.has_value_str()) {
- mProto->write(FIELD_TYPE_STRING | FIELD_ID_VALUE_STR, kv.value_str());
+ protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_VALUE_STR, kv.value_str());
} else if (kv.has_value_int()) {
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
} else if (kv.has_value_bool()) {
- mProto->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
+ protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
} else if (kv.has_value_float()) {
- mProto->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
+ protoOutput->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
}
- mProto->end(dimensionToken);
+ protoOutput->end(dimensionToken);
}
// Then fill bucket_info (CountBucketInfo).
for (const auto& bucket : counter.second) {
- long long bucketInfoToken =
- mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
- (long long)bucket.mBucketStartNs);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
- (long long)bucket.mBucketEndNs);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_COUNT, (long long)bucket.mCount);
- mProto->end(bucketInfoToken);
+ long long bucketInfoToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+ (long long)bucket.mBucketStartNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+ (long long)bucket.mBucketEndNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_COUNT, (long long)bucket.mCount);
+ protoOutput->end(bucketInfoToken);
VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
(long long)bucket.mBucketEndNs, (long long)bucket.mCount);
}
- mProto->end(wrapperToken);
+ protoOutput->end(wrapperToken);
}
- mProto->end(mProtoToken);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
- (long long)mCurrentBucketStartTimeNs);
+
+ protoOutput->end(protoToken);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
mPastBuckets.clear();
+ mStartTimeNs = mCurrentBucketStartTimeNs;
+
// TODO: Clear mDimensionKeyMap once the report is dumped.
}
-std::unique_ptr<std::vector<uint8_t>> CountMetricProducer::onDumpReport() {
- long long endTime = time(nullptr) * NS_PER_SEC;
- VLOG("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(endTime);
-
- // TODO(yanglu): merge these three functions to one to avoid three locks.
- serializeBuckets();
-
- std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
-
- startNewProtoOutputStream(endTime);
-
- return buffer;
-}
-
-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());
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
mCondition = conditionMet;
}
-bool CountMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) {
- std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
+bool CountMetricProducer::hitGuardRailLocked(const HashableDimensionKey& newKey) {
if (mCurrentSlicedCounter->find(newKey) != mCurrentSlicedCounter->end()) {
return false;
}
@@ -209,48 +184,47 @@
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);
- // ===========GuardRail==============
- if (hitGuardRail(eventKey)) {
+ if (condition == false) {
return;
}
- // TODO(yanglu): move the following logic to a seperate function to make it lockable.
- {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
- if (condition == false) {
+ auto it = mCurrentSlicedCounter->find(eventKey);
+
+ if (it == mCurrentSlicedCounter->end()) {
+ // ===========GuardRail==============
+ if (hitGuardRailLocked(eventKey)) {
return;
}
- auto it = mCurrentSlicedCounter->find(eventKey);
- if (it == mCurrentSlicedCounter->end()) {
- // create a counter for the new key
- mCurrentSlicedCounter->insert({eventKey, 1});
- } else {
- // increment the existing value
- auto& count = it->second;
- count++;
- }
- const int64_t& count = mCurrentSlicedCounter->find(eventKey)->second;
- for (auto& tracker : mAnomalyTrackers) {
- tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey, count);
- }
- VLOG("metric %s %s->%lld", mMetric.name().c_str(), eventKey.c_str(), (long long)(count));
+ // create a counter for the new key
+ (*mCurrentSlicedCounter)[eventKey] = 1;
+ } else {
+ // increment the existing value
+ auto& count = it->second;
+ count++;
}
+
+ for (auto& tracker : mAnomalyTrackers) {
+ tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey,
+ mCurrentSlicedCounter->find(eventKey)->second);
+ }
+
+ VLOG("metric %s %s->%lld", mMetric.name().c_str(), eventKey.c_str(),
+ (long long)(*mCurrentSlicedCounter)[eventKey]);
}
// 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) {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
-
+void CountMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
if (eventTimeNs < mCurrentBucketStartTimeNs + mBucketSizeNs) {
return;
}
@@ -283,8 +257,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 {
- std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
+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 164dfb2..21bd9d6 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -48,34 +48,33 @@
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:
- void serializeBuckets();
+ void onDumpReportLocked(const uint64_t dumpTimeNs,
+ android::util::ProtoOutputStream* protoOutput) 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);
const CountMetric mMetric;
@@ -87,7 +86,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 3b49b9a..9920f65 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -93,8 +93,6 @@
mConditionSliced = true;
}
- startNewProtoOutputStream(mStartTimeNs);
-
VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -103,48 +101,45 @@
VLOG("~DurationMetric() called");
}
-void DurationMetricProducer::startNewProtoOutputStream(long long startTime) {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
- 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);
- mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DURATION_METRICS);
+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);
}
unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
- const HashableDimensionKey& eventKey, vector<DurationBucket>& bucket) const {
+ 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);
}
}
-void DurationMetricProducer::finish() {
- // TODO: write the StatsLogReport to dropbox using
- // DropboxWriter.
-}
-
-void DurationMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+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) {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+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) {
@@ -152,8 +147,16 @@
}
}
-void DurationMetricProducer::SerializeBuckets() {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+void DurationMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
+ ProtoOutputStream* protoOutput) {
+ flushIfNeededLocked(dumpTimeNs);
+
+ protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
+ long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DURATION_METRICS);
+
+ VLOG("metric %s dump report now...", mMetric.name().c_str());
+
for (const auto& pair : mPastBuckets) {
const HashableDimensionKey& hashableKey = pair.first;
VLOG(" dimension key %s", hashableKey.c_str());
@@ -163,82 +166,56 @@
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);
+ protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
// First fill dimension (KeyValuePairs).
for (const auto& kv : it->second) {
- long long dimensionToken =
- mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DIMENSION);
- mProto->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
+ long long dimensionToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DIMENSION);
+ protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
if (kv.has_value_str()) {
- mProto->write(FIELD_TYPE_STRING | FIELD_ID_VALUE_STR, kv.value_str());
+ protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_VALUE_STR, kv.value_str());
} else if (kv.has_value_int()) {
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
} else if (kv.has_value_bool()) {
- mProto->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
+ protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
} else if (kv.has_value_float()) {
- mProto->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
+ protoOutput->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
}
- mProto->end(dimensionToken);
+ protoOutput->end(dimensionToken);
}
// Then fill bucket_info (DurationBucketInfo).
for (const auto& bucket : pair.second) {
- long long bucketInfoToken =
- mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
- (long long)bucket.mBucketStartNs);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
- (long long)bucket.mBucketEndNs);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_DURATION, (long long)bucket.mDuration);
- mProto->end(bucketInfoToken);
+ long long bucketInfoToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+ (long long)bucket.mBucketStartNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+ (long long)bucket.mBucketEndNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DURATION, (long long)bucket.mDuration);
+ protoOutput->end(bucketInfoToken);
VLOG("\t bucket [%lld - %lld] duration: %lld", (long long)bucket.mBucketStartNs,
(long long)bucket.mBucketEndNs, (long long)bucket.mDuration);
}
- mProto->end(wrapperToken);
+ protoOutput->end(wrapperToken);
}
- mProto->end(mProtoToken);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
- (long long)mCurrentBucketStartTimeNs);
+ protoOutput->end(protoToken);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
+ mPastBuckets.clear();
+ mStartTimeNs = mCurrentBucketStartTimeNs;
}
-std::unique_ptr<std::vector<uint8_t>> DurationMetricProducer::onDumpReport() {
- VLOG("metric %s dump report now...", mMetric.name().c_str());
-
- 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);
-
- SerializeBuckets();
-
- std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
-
- startNewProtoOutputStream(endTime);
- // TODO: Properly clear the old buckets.
- return buffer;
-}
-
-void DurationMetricProducer::flushIfNeeded(uint64_t eventTime) {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+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 {
@@ -251,8 +228,7 @@
mCurrentBucketNum += numBucketsForward;
}
-bool DurationMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) {
- std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
+bool DurationMetricProducer::hitGuardRailLocked(const HashableDimensionKey& newKey) {
// the key is not new, we are good.
if (mCurrentSlicedDuration.find(newKey) != mCurrentSlicedDuration.end()) {
return false;
@@ -272,43 +248,38 @@
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());
- // TODO(yanglu): move the following logic to a seperate function to make it lockable.
- {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
- if (matcherIndex == mStopAllIndex) {
- for (auto& pair : mCurrentSlicedDuration) {
- pair.second->noteStopAll(event.GetTimestampNs());
- }
+ if (matcherIndex == mStopAllIndex) {
+ for (auto& pair : mCurrentSlicedDuration) {
+ pair.second->noteStopAll(event.GetTimestampNs());
+ }
+ return;
+ }
+
+ HashableDimensionKey atomKey = getHashableKey(getDimensionKey(event, mInternalDimension));
+
+ if (mCurrentSlicedDuration.find(eventKey) == mCurrentSlicedDuration.end()) {
+ if (hitGuardRailLocked(eventKey)) {
return;
}
+ mCurrentSlicedDuration[eventKey] = createDurationTracker(eventKey);
+ }
- HashableDimensionKey atomKey = getHashableKey(getDimensionKey(event, mInternalDimension));
+ auto it = mCurrentSlicedDuration.find(eventKey);
- if (mCurrentSlicedDuration.find(eventKey) == mCurrentSlicedDuration.end()) {
- if (hitGuardRail(eventKey)) {
- return;
- }
- mCurrentSlicedDuration[eventKey] =
- createDurationTracker(eventKey, mPastBuckets[eventKey]);
- }
- auto it = mCurrentSlicedDuration.find(eventKey);
-
- if (matcherIndex == mStartIndex) {
- it->second->noteStart(atomKey, condition, event.GetTimestampNs(), conditionKeys);
- } else if (matcherIndex == mStopIndex) {
- it->second->noteStop(atomKey, event.GetTimestampNs(), false);
- }
+ if (matcherIndex == mStartIndex) {
+ it->second->noteStart(atomKey, condition, event.GetTimestampNs(), conditionKeys);
+ } else if (matcherIndex == mStopIndex) {
+ it->second->noteStop(atomKey, event.GetTimestampNs(), false);
}
}
-size_t DurationMetricProducer::byteSize() const {
- std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
+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 68fff48..e509af4 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -45,43 +45,45 @@
virtual ~DurationMetricProducer();
- 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;
+ virtual sp<AnomalyTracker> createAnomalyTracker(const Alert &alert) 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:
- void SerializeBuckets();
+ void onDumpReportLocked(const uint64_t dumpTimeNs,
+ android::util::ProtoOutputStream* protoOutput) 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);
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
@@ -98,14 +100,19 @@
std::unordered_map<HashableDimensionKey, std::unique_ptr<DurationTracker>>
mCurrentSlicedDuration;
+ // Helper function to create a duration tracker given the metric aggregation type.
std::unique_ptr<DurationTracker> createDurationTracker(
- const HashableDimensionKey& eventKey, std::vector<DurationBucket>& bucket) const;
- bool hitGuardRail(const HashableDimensionKey& newKey);
+ 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 53f112a..217aff0 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -62,7 +62,7 @@
mConditionSliced = true;
}
- startNewProtoOutputStream(mStartTimeNs);
+ startNewProtoOutputStreamLocked();
VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
@@ -72,52 +72,57 @@
VLOG("~EventMetricProducer() called");
}
-void EventMetricProducer::startNewProtoOutputStream(long long startTime) {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+void EventMetricProducer::startNewProtoOutputStreamLocked() {
mProto = std::make_unique<ProtoOutputStream>();
- // TODO: We need to auto-generate the field IDs for StatsLogReport, EventMetricData,
- // and StatsEvent.
- mProto->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
- mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS);
}
-void EventMetricProducer::finish() {
+void EventMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
}
-void EventMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
-}
+std::unique_ptr<std::vector<uint8_t>> serializeProtoLocked(ProtoOutputStream& protoOutput) {
+ size_t bufferSize = protoOutput.size();
-std::unique_ptr<std::vector<uint8_t>> EventMetricProducer::onDumpReport() {
- long long endTime = time(nullptr) * NS_PER_SEC;
- // TODO(yanglu): make this section to an util function.
- {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
- mProto->end(mProtoToken);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, endTime);
+ std::unique_ptr<std::vector<uint8_t>> buffer(new std::vector<uint8_t>(bufferSize));
- size_t bufferSize = mProto->size();
- VLOG("metric %s dump report now... proto size: %zu ", mMetric.name().c_str(), bufferSize);
+ size_t pos = 0;
+ auto it = protoOutput.data();
+ while (it.readBuffer() != NULL) {
+ size_t toRead = it.currentToRead();
+ std::memcpy(&((*buffer)[pos]), it.readBuffer(), toRead);
+ pos += toRead;
+ it.rp()->move(toRead);
}
- std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
-
- startNewProtoOutputStream(endTime);
-
return buffer;
}
-void EventMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
+void EventMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
+ ProtoOutputStream* protoOutput) {
+ protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
+
+ 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 = serializeProtoLocked(*mProto);
+
+ protoOutput->write(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS,
+ reinterpret_cast<char*>(buffer.get()->data()), buffer.get()->size());
+
+ startNewProtoOutputStreamLocked();
+ mStartTimeNs = dumpTimeNs;
+}
+
+void EventMetricProducer::onConditionChangedLocked(const bool conditionMet,
+ const uint64_t eventTime) {
VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
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) {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
if (!condition) {
return;
}
@@ -131,8 +136,7 @@
mProto->end(wrapperToken);
}
-size_t EventMetricProducer::byteSize() const {
- std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
+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..75ccf47 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -40,34 +40,38 @@
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();
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;
+
+ void onDumpReportLocked(const uint64_t dumpTimeNs,
+ android::util::ProtoOutputStream* protoOutput) 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;
+
+ // Maps to a EventMetricDataWrapper. Storing atom events in ProtoOutputStream
+ // is more space efficient than storing LogEvent.
+ std::unique_ptr<android::util::ProtoOutputStream> mProto;
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index ed4c760..55d84e0 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -91,29 +91,27 @@
metric.bucket().bucket_size_millis());
}
- startNewProtoOutputStream(mStartTimeNs);
-
VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
GaugeMetricProducer::~GaugeMetricProducer() {
VLOG("~GaugeMetricProducer() called");
+ if (mPullTagId != -1) {
+ mStatsPullerManager.UnRegisterReceiver(mPullTagId, this);
+ }
}
-void GaugeMetricProducer::startNewProtoOutputStream(long long startTime) {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
- 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);
- mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_GAUGE_METRICS);
-}
+void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
+ ProtoOutputStream* protoOutput) {
+ VLOG("gauge metric %s dump report now...", mMetric.name().c_str());
-void GaugeMetricProducer::finish() {
-}
+ flushIfNeededLocked(dumpTimeNs);
-void GaugeMetricProducer::SerializeBuckets() {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+ protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
+ long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_GAUGE_METRICS);
+
for (const auto& pair : mPastBuckets) {
const HashableDimensionKey& hashableKey = pair.first;
auto it = mDimensionKeyMap.find(hashableKey);
@@ -124,106 +122,81 @@
VLOG(" dimension key %s", hashableKey.c_str());
long long wrapperToken =
- mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
+ protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
// First fill dimension (KeyValuePairs).
for (const auto& kv : it->second) {
- long long dimensionToken =
- mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DIMENSION);
- mProto->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
+ long long dimensionToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DIMENSION);
+ protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
if (kv.has_value_str()) {
- mProto->write(FIELD_TYPE_STRING | FIELD_ID_VALUE_STR, kv.value_str());
+ protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_VALUE_STR, kv.value_str());
} else if (kv.has_value_int()) {
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
} else if (kv.has_value_bool()) {
- mProto->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
+ protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
} else if (kv.has_value_float()) {
- mProto->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
+ protoOutput->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
}
- mProto->end(dimensionToken);
+ protoOutput->end(dimensionToken);
}
// Then fill bucket_info (GaugeBucketInfo).
for (const auto& bucket : pair.second) {
- long long bucketInfoToken =
- mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
- (long long)bucket.mBucketStartNs);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
- (long long)bucket.mBucketEndNs);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_GAUGE, (long long)bucket.mGauge);
- mProto->end(bucketInfoToken);
+ long long bucketInfoToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+ (long long)bucket.mBucketStartNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+ (long long)bucket.mBucketEndNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_GAUGE, (long long)bucket.mGauge);
+ protoOutput->end(bucketInfoToken);
VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
(long long)bucket.mBucketEndNs, (long long)bucket.mGauge);
}
- mProto->end(wrapperToken);
+ protoOutput->end(wrapperToken);
}
- mProto->end(mProtoToken);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
- (long long)mCurrentBucketStartTimeNs);
+ protoOutput->end(protoToken);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
+
mPastBuckets.clear();
-}
-
-std::unique_ptr<std::vector<uint8_t>> GaugeMetricProducer::onDumpReport() {
- 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);
-
- SerializeBuckets();
-
- std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
-
- startNewProtoOutputStream(time(nullptr) * NS_PER_SEC);
- return buffer;
-
+ mStartTimeNs = mCurrentBucketStartTimeNs;
// TODO: Clear mDimensionKeyMap once the report is dumped.
}
-void GaugeMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
+void GaugeMetricProducer::onConditionChangedLocked(const bool conditionMet,
+ const uint64_t eventTime) {
VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
+ flushIfNeededLocked(eventTime);
+ mCondition = conditionMet;
- // flushIfNeeded holds the write lock and is thread-safe.
- flushIfNeeded(eventTime);
-
+ // Push mode. No need to proactively pull the gauge data.
+ if (mPullTagId == -1) {
+ return;
+ }
+ if (!mCondition) {
+ return;
+ }
+ // Already have gauge metric for the current bucket, do not do it again.
+ if (mCurrentSlicedBucket->size() > 0) {
+ return;
+ }
vector<std::shared_ptr<LogEvent>> allData;
- // The following section is to update the condition and re-pull the gauge.
- // TODO(yanglu): make it a seperate lockable function.
- {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
-
- mCondition = conditionMet;
-
- // Push mode. No need to proactively pull the gauge data.
- if (mPullTagId == -1) {
- return;
- }
- if (!mCondition) {
- return;
- }
- // Already have gauge metric for the current bucket, do not do it again.
- if (mCurrentSlicedBucket->size() > 0) {
- return;
- }
- if (!mStatsPullerManager.Pull(mPullTagId, &allData)) {
- ALOGE("Stats puller failed for tag: %d", mPullTagId);
- return;
- }
+ if (!mStatsPullerManager.Pull(mPullTagId, &allData)) {
+ ALOGE("Stats puller failed for tag: %d", mPullTagId);
+ return;
}
-
- // onMatchedLogEventInternal holds the write lock and is thread-safe.
for (const auto& data : allData) {
- onMatchedLogEvent(0, *data, false /*scheduledPull*/);
+ onMatchedLogEventLocked(0, *data, false /*scheduledPull*/);
}
+ flushIfNeededLocked(eventTime);
}
-void GaugeMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
+void GaugeMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
}
-int64_t GaugeMetricProducer::getGauge(const LogEvent& event) const {
+int64_t GaugeMetricProducer::getGauge(const LogEvent& event) {
status_t err = NO_ERROR;
int64_t val = event.GetLong(mMetric.gauge_field(), &err);
if (err == NO_ERROR) {
@@ -235,14 +208,14 @@
}
void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
- // onMatchedLogEventInternal holds the write lock and is thread-safe.
+ 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) {
- std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
+bool GaugeMetricProducer::hitGuardRailLocked(const HashableDimensionKey& newKey) {
if (mCurrentSlicedBucket->find(newKey) != mCurrentSlicedBucket->end()) {
return false;
}
@@ -262,36 +235,36 @@
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) {
- uint64_t eventTimeNs = event.GetTimestampNs();
- flushIfNeeded(eventTimeNs);
-
if (condition == false) {
return;
}
- const long gauge = getGauge(event);
- if (gauge < 0) {
- return;
- }
- if (hitGuardRail(eventKey)) {
- return;
- }
-
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+ uint64_t eventTimeNs = event.GetTimestampNs();
if (eventTimeNs < mCurrentBucketStartTimeNs) {
VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
(long long)mCurrentBucketStartTimeNs);
return;
}
+ // When the event happens in a new bucket, flush the old buckets.
+ if (eventTimeNs >= mCurrentBucketStartTimeNs + mBucketSizeNs) {
+ flushIfNeededLocked(eventTimeNs);
+ }
+
// For gauge metric, we just simply use the first gauge in the given bucket.
if (!mCurrentSlicedBucket->empty()) {
return;
}
+ const long gauge = getGauge(event);
+ if (gauge >= 0) {
+ if (hitGuardRailLocked(eventKey)) {
+ return;
+ }
(*mCurrentSlicedBucket)[eventKey] = gauge;
+ }
for (auto& tracker : mAnomalyTrackers) {
tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey, gauge);
}
@@ -302,8 +275,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) {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+void GaugeMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
if (eventTimeNs < mCurrentBucketStartTimeNs + mBucketSizeNs) {
return;
}
@@ -336,8 +308,7 @@
(long long)mCurrentBucketStartTimeNs);
}
-size_t GaugeMetricProducer::byteSize() const {
- std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
+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 8df6111..e4bda02 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -56,35 +56,37 @@
// 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:
- void SerializeBuckets();
+ void onDumpReportLocked(const uint64_t dumpTimeNs,
+ android::util::ProtoOutputStream* protoOutput) 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);
// The default bucket size for gauge metric is 1 second.
static const uint64_t kDefaultGaugemBucketSizeNs = 1000 * 1000 * 1000;
+
const GaugeMetric mMetric;
StatsPullerManager mStatsPullerManager;
@@ -98,9 +100,10 @@
// The current bucket.
std::shared_ptr<DimToValMap> mCurrentSlicedBucket = std::make_shared<DimToValMap>();
- int64_t getGauge(const LogEvent& event) const;
+ 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 7542a94..5a0a7c7f 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -21,9 +21,8 @@
using std::map;
-void MetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event,
- bool scheduledPull) {
- std::unique_lock<std::shared_timed_mutex> writeLock(mRWMutex);
+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,30 +59,9 @@
} else {
condition = mCondition;
}
- // Unlock as onMatchedLogEventInternal is threadsafe.
- writeLock.unlock();
- onMatchedLogEventInternal(matcherIndex, eventKey, conditionKeys, condition, event,
- scheduledPull);
-}
-
-std::unique_ptr<std::vector<uint8_t>> MetricProducer::serializeProto() {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
-
- size_t bufferSize = mProto->size();
-
- std::unique_ptr<std::vector<uint8_t>> buffer(new std::vector<uint8_t>(bufferSize));
-
- size_t pos = 0;
- auto it = mProto->data();
- while (it.readBuffer() != NULL) {
- size_t toRead = it.currentToRead();
- std::memcpy(&((*buffer)[pos]), it.readBuffer(), toRead);
- pos += toRead;
- it.rp()->move(toRead);
- }
-
- return buffer;
+ onMatchedLogEventInternalLocked(matcherIndex, eventKey, conditionKeys, condition, event,
+ scheduledPull);
}
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 27343ad..ef2ef29 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -54,42 +54,64 @@
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);
+ }
- // 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 {
+ bool isConditionSliced() const {
+ std::lock_guard<std::mutex> lock(mMutex);
return mConditionSliced;
};
+ // Output the metrics data to [protoOutput]. All metrics reports end with the same timestamp.
+ void onDumpReport(const uint64_t dumpTimeNs, android::util::ProtoOutputStream* protoOutput) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return onDumpReportLocked(dumpTimeNs, protoOutput);
+ }
+
// 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 void onDumpReportLocked(const uint64_t dumpTimeNs,
+ android::util::ProtoOutputStream* protoOutput) = 0;
+ virtual size_t byteSizeLocked() const = 0;
+
const ConfigKey mConfigKey;
- const uint64_t mStartTimeNs;
+ // The start time for the current in memory metrics data.
+ uint64_t mStartTimeNs;
uint64_t mCurrentBucketStartTimeNs;
@@ -111,7 +133,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;
@@ -123,29 +145,23 @@
* [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;
- std::unique_ptr<android::util::ProtoOutputStream> mProto;
+ // 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);
- long long mProtoToken;
-
- // Read/Write mutex to make the producer thread-safe.
- // TODO(yanglu): replace with std::shared_mutex when available in libc++.
- mutable std::shared_timed_mutex mRWMutex;
-
- virtual void startNewProtoOutputStream(long long timestamp) = 0;
-
- std::unique_ptr<std::vector<uint8_t>> serializeProto();
+ mutable std::mutex mMutex;
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index e986c1a..0510fff 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -27,6 +27,11 @@
#include "stats_util.h"
#include <log/logprint.h>
+
+using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_MESSAGE;
+using android::util::ProtoOutputStream;
+
using std::make_unique;
using std::set;
using std::string;
@@ -37,9 +42,11 @@
namespace os {
namespace statsd {
+const int FIELD_ID_METRICS = 1;
+
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 +54,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;
}
@@ -65,21 +72,17 @@
return mConfigValid;
}
-void MetricsManager::finish() {
- for (auto& metricProducer : mAllMetricProducers) {
- metricProducer->finish();
- }
-}
-
-vector<std::unique_ptr<vector<uint8_t>>> MetricsManager::onDumpReport() {
+void MetricsManager::onDumpReport(ProtoOutputStream* protoOutput) {
VLOG("=========================Metric Reports Start==========================");
+ uint64_t dumpTimeStampNs = time(nullptr) * NS_PER_SEC;
// one StatsLogReport per MetricProduer
- vector<std::unique_ptr<vector<uint8_t>>> reportList;
for (auto& metric : mAllMetricProducers) {
- reportList.push_back(metric->onDumpReport());
+ long long token =
+ protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
+ metric->onDumpReport(dumpTimeStampNs, protoOutput);
+ protoOutput->end(token);
}
VLOG("=========================Metric Reports End==========================");
- return reportList;
}
// Consume the stats log if it's interesting to this metric.
@@ -95,10 +98,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 +145,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 */);
}
}
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 62b4c87..34ea667 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -36,27 +36,24 @@
public:
MetricsManager(const ConfigKey& configKey, const StatsdConfig& config);
- ~MetricsManager();
+ virtual ~MetricsManager();
// Return whether the configuration is valid.
bool isConfigValid() const;
void onLogEvent(const LogEvent& event);
- // Called when everything should wrap up. We are about to finish (e.g., new config comes).
- void finish();
-
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 void onDumpReport(android::util::ProtoOutputStream* protoOutput);
// 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;
@@ -71,8 +68,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 eed7841..c20c302 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -97,9 +97,6 @@
mStatsPullerManager->RegisterReceiver(mPullTagId, this,
metric.bucket().bucket_size_millis());
}
-
- startNewProtoOutputStream(mStartTimeNs);
-
VLOG("value metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -120,25 +117,18 @@
}
}
-void ValueMetricProducer::startNewProtoOutputStream(long long startTime) {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
- 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);
- mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_VALUE_METRICS);
-}
-
-void ValueMetricProducer::finish() {
- // TODO: write the StatsLogReport to dropbox using
- // DropboxWriter.
-}
-
-void ValueMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
+void ValueMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
}
-void ValueMetricProducer::SerializeBuckets() {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+void ValueMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
+ ProtoOutputStream* protoOutput) {
+ VLOG("metric %s dump report now...", mMetric.name().c_str());
+ flushIfNeededLocked(dumpTimeNs);
+ protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
+ long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_VALUE_METRICS);
+
for (const auto& pair : mPastBuckets) {
const HashableDimensionKey& hashableKey = pair.first;
VLOG(" dimension key %s", hashableKey.c_str());
@@ -148,117 +138,98 @@
continue;
}
long long wrapperToken =
- mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
+ protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
// First fill dimension (KeyValuePairs).
for (const auto& kv : it->second) {
- long long dimensionToken =
- mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DIMENSION);
- mProto->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
+ long long dimensionToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DIMENSION);
+ protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
if (kv.has_value_str()) {
- mProto->write(FIELD_TYPE_STRING | FIELD_ID_VALUE_STR, kv.value_str());
+ protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_VALUE_STR, kv.value_str());
} else if (kv.has_value_int()) {
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
} else if (kv.has_value_bool()) {
- mProto->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
+ protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
} else if (kv.has_value_float()) {
- mProto->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
+ protoOutput->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
}
- mProto->end(dimensionToken);
+ protoOutput->end(dimensionToken);
}
// Then fill bucket_info (ValueBucketInfo).
for (const auto& bucket : pair.second) {
- long long bucketInfoToken =
- mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
- (long long)bucket.mBucketStartNs);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
- (long long)bucket.mBucketEndNs);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE, (long long)bucket.mValue);
- mProto->end(bucketInfoToken);
+ long long bucketInfoToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+ (long long)bucket.mBucketStartNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+ (long long)bucket.mBucketEndNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE, (long long)bucket.mValue);
+ protoOutput->end(bucketInfoToken);
VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
(long long)bucket.mBucketEndNs, (long long)bucket.mValue);
}
- mProto->end(wrapperToken);
+ protoOutput->end(wrapperToken);
}
- mProto->end(mProtoToken);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
- (long long)mCurrentBucketStartTimeNs);
- mPastBuckets.clear();
-}
+ protoOutput->end(protoToken);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
-std::unique_ptr<std::vector<uint8_t>> ValueMetricProducer::onDumpReport() {
VLOG("metric %s dump report now...", mMetric.name().c_str());
-
- SerializeBuckets();
- std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
-
- startNewProtoOutputStream(time(nullptr) * NS_PER_SEC);
-
- return buffer;
+ mPastBuckets.clear();
+ mStartTimeNs = mCurrentBucketStartTimeNs;
// TODO: Clear mDimensionKeyMap once the report is dumped.
}
-void ValueMetricProducer::onConditionChanged(const bool condition, const uint64_t eventTime) {
- vector<shared_ptr<LogEvent>> allData;
+void ValueMetricProducer::onConditionChangedLocked(const bool condition, const uint64_t eventTime) {
+ mCondition = condition;
- // TODO(yanglu): move the following logic to a seperate function to make it lockable.
- {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
- mCondition = condition;
+ if (eventTime < mCurrentBucketStartTimeNs) {
+ return;
+ }
- if (mPullTagId == -1) {
- return;
- }
-
+ if (mPullTagId != -1) {
if (mCondition == true) {
mStatsPullerManager->RegisterReceiver(mPullTagId, this,
mMetric.bucket().bucket_size_millis());
} else if (mCondition == false) {
mStatsPullerManager->UnRegisterReceiver(mPullTagId, this);
}
- if (!mStatsPullerManager->Pull(mPullTagId, &allData)) {
- return;
- }
- }
- if (allData.size() == 0) {
+ vector<shared_ptr<LogEvent>> allData;
+ if (mStatsPullerManager->Pull(mPullTagId, &allData)) {
+ if (allData.size() == 0) {
+ return;
+ }
+ for (const auto& data : allData) {
+ onMatchedLogEventLocked(0, *data, false);
+ }
+ flushIfNeededLocked(eventTime);
+ }
return;
}
-
- // onMatchedLogEventInternal holds the write lock and is thread-safe.
- for (const auto& data : allData) {
- onMatchedLogEvent(0, *data, false);
- }
- // flushIfNeeded holds the write lock and is thread-safe.
- flushIfNeeded(eventTime);
-}
-
-bool ValueMetricProducer::IsConditionMet() const {
- std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
- return mCondition == true || !mMetric.has_condition();
}
void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
- if (IsConditionMet()) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (mCondition == true || !mMetric.has_condition()) {
if (allData.size() == 0) {
return;
}
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) {
- std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
+bool ValueMetricProducer::hitGuardRailLocked(const HashableDimensionKey& newKey) {
// ===========GuardRail==============
// 1. Report the tuple count if the tuple count > soft limit
if (mCurrentSlicedBucket.find(newKey) != mCurrentSlicedBucket.end()) {
@@ -279,75 +250,58 @@
return false;
}
-void ValueMetricProducer::onMatchedLogEventInternal_pull(const uint64_t& eventTimeNs,
- const HashableDimensionKey& eventKey,
- const long& value, bool scheduledPull) {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
-
- if (eventTimeNs < mCurrentBucketStartTimeNs) {
- VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
- (long long)mCurrentBucketStartTimeNs);
- return;
- }
- Interval& interval = mCurrentSlicedBucket[eventKey];
- if (scheduledPull) {
- // scheduled pull always sets beginning of current bucket and end
- // of next bucket
- if (interval.raw.size() > 0) {
- interval.raw.back().second = value;
- } else {
- interval.raw.push_back(make_pair(value, value));
- }
- Interval& nextInterval = mNextSlicedBucket[eventKey];
- if (nextInterval.raw.size() == 0) {
- nextInterval.raw.push_back(make_pair(value, 0));
- } else {
- nextInterval.raw.front().first = value;
- }
- } else {
- if (mCondition == true) {
- interval.raw.push_back(make_pair(value, 0));
- } else {
- if (interval.raw.size() != 0) {
- interval.raw.back().second = value;
- } else {
- interval.tainted = true;
- VLOG("Data on condition true missing!");
- }
- }
- }
-}
-
-void ValueMetricProducer::onMatchedLogEventInternal_push(const uint64_t& eventTimeNs,
- const HashableDimensionKey& eventKey,
- const long& value) {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
- if (eventTimeNs < mCurrentBucketStartTimeNs) {
- VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
- (long long)mCurrentBucketStartTimeNs);
- return;
- }
- mCurrentSlicedBucket[eventKey].raw.push_back(make_pair(value, 0));
-}
-
-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) {
uint64_t eventTimeNs = event.GetTimestampNs();
- long value = get_value(event);
- if (hitGuardRail(eventKey)) {
+ if (eventTimeNs < mCurrentBucketStartTimeNs) {
+ VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
+ (long long)mCurrentBucketStartTimeNs);
return;
}
+
+ if (hitGuardRailLocked(eventKey)) {
+ return;
+ }
+ Interval& interval = mCurrentSlicedBucket[eventKey];
+
+ long value = get_value(event);
+
if (mPullTagId != -1) {
- onMatchedLogEventInternal_pull(eventTimeNs, eventKey, value, scheduledPull);
+ if (scheduledPull) {
+ // scheduled pull always sets beginning of current bucket and end
+ // of next bucket
+ if (interval.raw.size() > 0) {
+ interval.raw.back().second = value;
+ } else {
+ interval.raw.push_back(make_pair(value, value));
+ }
+ Interval& nextInterval = mNextSlicedBucket[eventKey];
+ if (nextInterval.raw.size() == 0) {
+ nextInterval.raw.push_back(make_pair(value, 0));
+ } else {
+ nextInterval.raw.front().first = value;
+ }
+ } else {
+ if (mCondition == true) {
+ interval.raw.push_back(make_pair(value, 0));
+ } else {
+ if (interval.raw.size() != 0) {
+ interval.raw.back().second = value;
+ } else {
+ interval.tainted = true;
+ VLOG("Data on condition true missing!");
+ }
+ }
+ }
} else {
- flushIfNeeded(eventTimeNs);
- onMatchedLogEventInternal_push(eventTimeNs, eventKey, value);
+ flushIfNeededLocked(eventTimeNs);
+ interval.raw.push_back(make_pair(value, 0));
}
}
-long ValueMetricProducer::get_value(const LogEvent& event) const {
+long ValueMetricProducer::get_value(const LogEvent& event) {
status_t err = NO_ERROR;
long val = event.GetLong(mMetric.value_field(), &err);
if (err == NO_ERROR) {
@@ -358,8 +312,7 @@
}
}
-void ValueMetricProducer::flushIfNeeded(const uint64_t eventTimeNs) {
- std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+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));
@@ -407,8 +360,7 @@
(long long)mCurrentBucketStartTimeNs);
}
-size_t ValueMetricProducer::byteSize() const {
- std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
+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 e87e9da..8d60ff6 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -44,43 +44,35 @@
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:
- void onMatchedLogEventInternal_pull(const uint64_t& eventTimeNs,
- const HashableDimensionKey& eventKey, const long& value,
- bool scheduledPull);
- void onMatchedLogEventInternal_push(const uint64_t& eventTimeNs,
- const HashableDimensionKey& eventKey, const long& value);
+ void onDumpReportLocked(const uint64_t dumpTimeNs,
+ android::util::ProtoOutputStream* protoOutput) override;
- void SerializeBuckets();
+ // Internal interface to handle condition change.
+ void onConditionChangedLocked(const bool conditionMet, const uint64_t eventTime) override;
- bool IsConditionMet() const;
+ // 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);
const ValueMetric mMetric;
@@ -110,9 +102,10 @@
// TODO: Add a lock to mPastBuckets.
std::unordered_map<HashableDimensionKey, std::vector<ValueBucket>> mPastBuckets;
- long get_value(const LogEvent& event) const;
+ 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 abdfbc0..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;
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 9e5163f..943becb 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -40,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;
@@ -64,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);
@@ -93,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:
@@ -118,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.
@@ -142,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;
@@ -191,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,
@@ -217,7 +217,7 @@
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;
}
@@ -232,7 +232,7 @@
}
} 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;
}
}
@@ -254,43 +254,43 @@
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;
@@ -303,7 +303,7 @@
}
} 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;
}
}
@@ -325,7 +325,7 @@
return false;
}
int trackerIndex;
- if (!handleMetricWithLogTrackers(metric.what(), metricIndex, false, allLogEntryMatchers,
+ if (!handleMetricWithLogTrackers(metric.what(), metricIndex, false, allAtomMatchers,
logTrackerMap, trackerToMetricMap, trackerIndex)) {
return false;
}
@@ -340,7 +340,7 @@
}
} 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;
}
}
@@ -363,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()) {
@@ -390,7 +390,7 @@
}
} 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;
}
}
@@ -412,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()) {
@@ -439,7 +439,7 @@
}
} 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;
}
}
@@ -468,26 +468,18 @@
return false;
}
const int metricIndex = itr->second;
- if (alert.trigger_if_sum_gt() >
- (int64_t) alert.number_of_buckets()
- * allMetricProducers[metricIndex]->getBuckeSizeInNs()) {
- ALOGW("invalid alert: threshold (%lld) > possible recordable value (%d x %lld)",
- alert.trigger_if_sum_gt(), alert.number_of_buckets(),
- (long long) allMetricProducers[metricIndex]->getBuckeSizeInNs());
- return false;
+ sp<MetricProducer> metric = allMetricProducers[metricIndex];
+ sp<AnomalyTracker> anomalyTracker = metric->createAnomalyTracker(alert);
+ if (anomalyTracker != nullptr) {
+ metric->addAnomalyTracker(anomalyTracker);
+ allAnomalyTrackers.push_back(anomalyTracker);
}
-
- // TODO: Give each MetricProducer a method called createAnomalyTracker(alert), which
- // creates either an AnomalyTracker or a DurationAnomalyTracker and returns it.
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
- allMetricProducers[metricIndex]->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,
@@ -498,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;
}
@@ -510,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 e7e1d43..20d9d5c 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -22,7 +22,7 @@
option java_package = "com.android.os";
option java_outer_classname = "StatsLog";
-import "frameworks/base/cmds/statsd/src/atoms_copy.proto";
+import "frameworks/base/cmds/statsd/src/atoms.proto";
message KeyValuePair {
optional int32 key = 1;
@@ -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 alerted_times = 2;
+ }
+
message ConfigStats {
optional int32 uid = 1;
optional string name = 2;
@@ -210,6 +215,7 @@
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;
@@ -220,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/stats_util.cpp b/cmds/statsd/src/stats_util.cpp
index fcce2ff..bfa3254 100644
--- a/cmds/statsd/src/stats_util.cpp
+++ b/cmds/statsd/src/stats_util.cpp
@@ -15,119 +15,11 @@
*/
#include "stats_util.h"
-#include <log/log_event_list.h>
namespace android {
namespace os {
namespace statsd {
-static inline uint32_t get4LE(const char* src) {
- return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
-}
-
-int getTagId(log_msg msg) {
- return get4LE(msg.msg());
-}
-
-EventMetricData parse(log_msg msg) {
- // dump all statsd logs to dropbox for now.
- // TODO: Add filtering, aggregation, etc.
- EventMetricData eventMetricData;
-
- // set tag.
- int tag = getTagId(msg);
- // TODO: Replace the following line when we can serialize on the fly.
- // eventMetricData.set_tag(tag);
-
- // set timestamp of the event.
- eventMetricData.set_timestamp_nanos(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec);
-
- // start iterating k,v pairs.
- android_log_context context =
- create_android_log_parser(const_cast<log_msg*>(&msg)->msg() + sizeof(uint32_t),
- const_cast<log_msg*>(&msg)->len() - sizeof(uint32_t));
- android_log_list_element elem;
-
- if (context) {
- memset(&elem, 0, sizeof(elem));
- size_t index = 0;
- int32_t key = -1;
-
- do {
- elem = android_log_read_next(context);
- switch ((int)elem.type) {
- case EVENT_TYPE_INT:
- if (index % 2 == 0) {
- key = elem.data.int32;
- } else {
- // TODO: Fix the following lines when we can serialize on the fly.
- /*
- int32_t val = elem.data.int32;
- KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
- keyValuePair->set_key(key);
- keyValuePair->set_value_int(val);
- */
- }
- index++;
- break;
- case EVENT_TYPE_FLOAT:
- if (index % 2 == 1) {
- // TODO: Fix the following lines when we can serialize on the fly.
- /*
- float val = elem.data.float32;
- KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
- keyValuePair->set_key(key);
- keyValuePair->set_value_float(val);
- */
- }
- index++;
- break;
- case EVENT_TYPE_STRING:
- if (index % 2 == 1) {
- // TODO: Fix the following lines when we can serialize on the fly.
- /*
- char* val = elem.data.string;
- KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
- keyValuePair->set_key(key);
- keyValuePair->set_value_str(val);
- */
- }
- index++;
- break;
- case EVENT_TYPE_LONG:
- if (index % 2 == 1) {
- // TODO: Fix the following lines when we can serialize on the fly.
- /*
- int64_t val = elem.data.int64;
- KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
- keyValuePair->set_key(key);
- keyValuePair->set_value_int(val);
- */
- }
- index++;
- break;
- case EVENT_TYPE_LIST:
- break;
- case EVENT_TYPE_LIST_STOP:
- break;
- case EVENT_TYPE_UNKNOWN:
- break;
- default:
- elem.complete = true;
- break;
- }
-
- if (elem.complete) {
- break;
- }
- } while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
-
- android_log_destroy(&context);
- }
-
- return eventMetricData;
-}
-
// There is no existing hash function for the dimension key ("repeated KeyValuePair").
// Temporarily use a string concatenation as the hashable key.
// TODO: Find a better hash function for std::vector<KeyValuePair>.
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
index b7d8f97..594561d 100644
--- a/cmds/statsd/src/stats_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -16,11 +16,7 @@
#pragma once
-#include "logd/LogReader.h"
-#include "storage/DropboxWriter.h"
-
-#include <log/logprint.h>
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include <unordered_map>
@@ -29,7 +25,6 @@
namespace statsd {
#define DEFAULT_DIMENSION_KEY ""
-#define MATCHER_NOT_FOUND -2
typedef std::string HashableDimensionKey;
@@ -37,10 +32,6 @@
typedef std::unordered_map<HashableDimensionKey, int64_t> DimToValMap;
-EventMetricData parse(log_msg msg);
-
-int getTagId(log_msg msg);
-
std::string getHashableKey(std::vector<KeyValuePair> key);
} // namespace statsd
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/DropboxReader.cpp b/cmds/statsd/src/storage/DropboxReader.cpp
deleted file mode 100644
index c561959..0000000
--- a/cmds/statsd/src/storage/DropboxReader.cpp
+++ /dev/null
@@ -1,120 +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.
- */
-#include <android-base/file.h>
-#include <android/os/DropBoxManager.h>
-#include <androidfw/ZipUtils.h>
-
-#include "storage/DropboxReader.h"
-
-using android::base::unique_fd;
-using android::binder::Status;
-using android::os::DropBoxManager;
-using android::sp;
-using android::String16;
-using android::ZipUtils;
-using std::vector;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-status_t DropboxReader::readStatsLogs(FILE* out, const string& tag, long msec) {
- sp<DropBoxManager> dropbox = new DropBoxManager();
- StatsLogReport logReport;
-
- long timestamp = msec;
- // instead of while(true), put a hard limit 1000. Dropbox won't have more than 1000 files.
- for (int i = 0; i < 1000; i++) {
- DropBoxManager::Entry entry;
- Status status = dropbox->getNextEntry(String16(tag.c_str()), timestamp, &entry);
- if (!status.isOk()) {
- ALOGD("No more entries, or failed to read. We can't tell unfortunately.");
- return android::OK;
- }
-
- const unique_fd& fd = entry.getFd();
-
- // use this timestamp for next query.
- timestamp = entry.getTimestamp();
-
- if (entry.getFlags() & DropBoxManager::IS_GZIPPED) {
- if (!parseFromGzipFile(fd, logReport)) {
- // Failed to parse from the file. Continue to fetch the next entry.
- continue;
- }
- } else {
- if (!parseFromFile(fd, logReport)) {
- // Failed to parse from the file. Continue to fetch the next entry.
- continue;
- }
- }
-
- printLog(out, logReport);
- }
- return android::OK;
-}
-
-bool DropboxReader::parseFromGzipFile(const unique_fd& fd, StatsLogReport& logReport) {
- FILE* file = fdopen(fd, "r");
- bool result = false;
- bool scanResult;
- int method;
- long compressedLen;
- long uncompressedLen;
- unsigned long crc32;
- scanResult = ZipUtils::examineGzip(file, &method, &uncompressedLen, &compressedLen, &crc32);
- if (scanResult && method == kCompressDeflated) {
- vector<uint8_t> buf(uncompressedLen);
- if (ZipUtils::inflateToBuffer(file, &buf[0], uncompressedLen, compressedLen)) {
- if (logReport.ParseFromArray(&buf[0], uncompressedLen)) {
- result = true;
- }
- }
- } else {
- ALOGE("This isn't a valid deflated gzip file");
- }
- fclose(file);
- return result;
-}
-
-// parse a non zipped file.
-bool DropboxReader::parseFromFile(const unique_fd& fd, StatsLogReport& logReport) {
- string content;
- if (!android::base::ReadFdToString(fd, &content)) {
- ALOGE("Failed to read file");
- return false;
- }
- if (!logReport.ParseFromString(content)) {
- ALOGE("failed to parse log entry from data");
- return false;
- }
- return true;
-}
-
-void DropboxReader::printLog(FILE* out, const StatsLogReport& logReport) {
- fprintf(out, "start_time_ns=%lld, end_time_ns=%lld, ", logReport.start_report_nanos(),
- logReport.end_report_nanos());
- for (int i = 0; i < logReport.event_metrics().data_size(); i++) {
- EventMetricData eventMetricData = logReport.event_metrics().data(i);
- // TODO: Pretty-print the proto.
- // fprintf(out, "EventMetricData=%s", eventMetricData.SerializeAsString().c_str());
- }
- fprintf(out, "\n");
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/storage/DropboxReader.h b/cmds/statsd/src/storage/DropboxReader.h
deleted file mode 100644
index a5a28d9..0000000
--- a/cmds/statsd/src/storage/DropboxReader.h
+++ /dev/null
@@ -1,52 +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.
- */
-
-#ifndef DROPBOX_READER_H
-#define DROPBOX_READER_H
-
-#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
-
-#include <stdint.h>
-#include <stdio.h>
-
-using android::base::unique_fd;
-using android::status_t;
-using std::string;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class DropboxReader {
-public:
- // msec is the start timestamp.
- static status_t readStatsLogs(FILE* out, const string& tag, long msec);
-
-private:
- static bool parseFromFile(const unique_fd& fd, StatsLogReport& logReport);
- static bool parseFromGzipFile(const unique_fd& fd, StatsLogReport& logReport);
- static void printLog(FILE* out, const StatsLogReport& logReport);
- enum {
- kCompressStored = 0, // no compression
- kCompressDeflated = 8, // standard deflate
- };
-};
-
-} // namespace statsd
-} // namespace os
-} // namespace android
-
-#endif // DROPBOX_READER_H
diff --git a/cmds/statsd/src/storage/DropboxWriter.cpp b/cmds/statsd/src/storage/DropboxWriter.cpp
deleted file mode 100644
index e59bdbd..0000000
--- a/cmds/statsd/src/storage/DropboxWriter.cpp
+++ /dev/null
@@ -1,64 +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.
- */
-
-#include <android/os/DropBoxManager.h>
-
-#include "storage/DropboxWriter.h"
-
-using android::binder::Status;
-using android::os::DropBoxManager;
-using android::sp;
-using android::String16;
-using std::vector;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-DropboxWriter::DropboxWriter(const string& tag) : mTag(tag), mLogReport(), mBufferSize(0) {
-}
-
-void DropboxWriter::addEventMetricData(const EventMetricData& eventMetricData) {
- flushIfNecessary(eventMetricData);
- EventMetricData* newEntry = mLogReport.mutable_event_metrics()->add_data();
- newEntry->CopyFrom(eventMetricData);
- mBufferSize += eventMetricData.ByteSize();
-}
-
-void DropboxWriter::flushIfNecessary(const EventMetricData& eventMetricData) {
- if (eventMetricData.ByteSize() + mBufferSize > kMaxSerializedBytes) {
- flush();
- }
-}
-
-void DropboxWriter::flush() {
- // now we get an exact byte size of the output
- const int numBytes = mLogReport.ByteSize();
- vector<uint8_t> buffer(numBytes);
- sp<DropBoxManager> dropbox = new DropBoxManager();
- mLogReport.SerializeToArray(&buffer[0], numBytes);
- Status status = dropbox->addData(String16(mTag.c_str()), &buffer[0], numBytes, 0 /* no flag */);
- if (!status.isOk()) {
- ALOGE("failed to write to dropbox");
- // TODO: What to do if flush fails??
- }
- mLogReport.Clear();
- mBufferSize = 0;
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/storage/DropboxWriter.h b/cmds/statsd/src/storage/DropboxWriter.h
deleted file mode 100644
index d72f103..0000000
--- a/cmds/statsd/src/storage/DropboxWriter.h
+++ /dev/null
@@ -1,72 +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.
- */
-
-#ifndef DROPBOX_WRITER_H
-#define DROPBOX_WRITER_H
-
-#include <utils/RefBase.h>
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-
-using std::string;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class DropboxWriter : public virtual RefBase {
-public:
- /* tag will be part of the file name, and used as the key to build the file index inside
- DropBoxManagerService.
- */
- DropboxWriter(const string& tag);
-
- void addEventMetricData(const EventMetricData& eventMetricData);
-
- /* Request a flush to dropbox. */
- void flush();
-
-private:
- /* Max *serialized* size of the logs kept in memory before flushing to dropbox.
- 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. DropboxManager will compress the file when the data is
- larger than 4KB. So the final file size is less than this number.
- */
- static const size_t kMaxSerializedBytes = 16 * 1024;
-
- const string mTag;
-
- /* Data that was captured for a single metric over a given interval of time. */
- StatsLogReport mLogReport;
-
- /* Current *serialized* size of the logs kept in memory.
- To save computation, we will not calculate the size of the StatsLogReport every time when a
- new entry is added, which would recursively call ByteSize() on every log entry. Instead, we
- keep the sum of all individual stats log entry sizes. The size of a proto is approximately
- the sum of the size of all member protos.
- */
- size_t mBufferSize = 0;
-
- /* Check if the buffer size exceeds the max buffer size when the new entry is added, and flush
- the logs to dropbox if true. */
- void flushIfNecessary(const EventMetricData& eventMetricData);
-};
-
-} // namespace statsd
-} // namespace os
-} // namespace android
-
-#endif // DROPBOX_WRITER_H
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 62f06a7..3a4dfda 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -30,7 +30,7 @@
namespace os {
namespace statsd {
-#define STATS_SERVICE_DIR "/data/system/stats-service"
+#define STATS_SERVICE_DIR "/data/misc/stats-service"
// for ConfigMetricsReportList
const int FIELD_ID_REPORTS = 2;
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 5384e0c..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,7 +165,7 @@
return config;
}
-StatsdConfig buildMissingCondition() {
+StatsdConfig buildMissingPredicate() {
StatsdConfig config;
config.set_name("12345");
@@ -175,11 +175,11 @@
metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
metric->set_condition("SOME_CONDITION");
- LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
eventMatcher->set_name("SCREEN_EVENT");
- SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->set_tag(2);
+ SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_tag(2);
return config;
}
@@ -188,20 +188,20 @@
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");
@@ -223,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;
}
@@ -267,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;
@@ -275,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());
@@ -285,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;
@@ -293,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));
}
@@ -301,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;
@@ -309,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));
}
@@ -317,37 +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, TestMissingCondition) {
- StatsdConfig config = buildMissingCondition();
+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, allLogEntryMatchers,
+ EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
}
-TEST(MetricsManagerTest, TestCircleConditionDependency) {
- StatsdConfig config = buildCircleConditions();
+TEST(MetricsManagerTest, TestCirclePredicateDependency) {
+ StatsdConfig config = buildCirclePredicates();
set<int> allTagIds;
- vector<sp<LogMatchingTracker>> allLogEntryMatchers;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
@@ -355,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));
}
@@ -363,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;
@@ -371,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..aff06ba
--- /dev/null
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -0,0 +1,119 @@
+// 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 {
+
+using android::util::ProtoOutputStream;
+
+#ifdef __ANDROID__
+
+/**
+ * Mock MetricsManager (ByteSize() is called).
+ */
+class MockMetricsManager : public MetricsManager {
+public:
+ MockMetricsManager() : MetricsManager(ConfigKey(1, "key"), StatsdConfig()) {
+ }
+
+ MOCK_METHOD0(byteSize, size_t());
+ MOCK_METHOD1(onDumpReport, void(ProtoOutputStream* output));
+};
+
+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
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 65c2a05..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);
+ 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);
+ 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 8b0b6a4..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;
@@ -243,11 +243,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());
@@ -257,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
@@ -268,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]);
@@ -280,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]);
@@ -292,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";
@@ -314,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";
@@ -329,11 +329,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());
@@ -343,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
@@ -354,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]);
@@ -366,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]);
@@ -378,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";
@@ -400,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;
@@ -413,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());
@@ -427,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
@@ -439,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]);
@@ -448,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]);
@@ -461,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());
@@ -470,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 a8193dd..312de1b 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -118,6 +118,10 @@
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);
@@ -142,7 +146,6 @@
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());
@@ -157,6 +160,13 @@
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).alerted_times());
+ EXPECT_EQ("alert2", configReport.alert_stats(alert1first ? 1 : 0).name());
+ EXPECT_EQ(1, configReport.alert_stats(alert1first ? 1 : 0).alerted_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());
@@ -169,6 +179,7 @@
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);
@@ -187,6 +198,10 @@
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).alerted_times());
}
TEST(StatsdStatsTest, TestAtomLog) {
@@ -224,6 +239,21 @@
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;
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index 2cbeaaa..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);
+ 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 85f5008..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);
+ 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 5d47437..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);
- 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 6913c81..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);
- 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);
- 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/Android.mk b/cmds/statsd/tools/dogfood/Android.mk
index 1bd5f30..6b0531d 100644
--- a/cmds/statsd/tools/dogfood/Android.mk
+++ b/cmds/statsd/tools/dogfood/Android.mk
@@ -16,19 +16,19 @@
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
-
-LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/../../src/
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := lite-static
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
LOCAL_PACKAGE_NAME := StatsdDogfood
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES += ../../src/stats_log.proto \
+ ../../src/atoms.proto
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/../../src/
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_STATIC_JAVA_LIBRARIES := platformprotoslite
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := lite
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
LOCAL_DEX_PREOPT := false
-include $(BUILD_PACKAGE)
\ No newline at end of file
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
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..0a0fd66
--- /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_PACKAGE_NAME := StatsdLoadtest
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES += ../../src/stats_log.proto \
+ ../../src/atoms.proto \
+ ../../src/statsd_config.proto
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/../../src/
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_STATIC_JAVA_LIBRARIES := platformprotoslite
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := lite
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_DEX_PREOPT := false
+LOCAL_PROGUARD_ENABLED := disabled
+
+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..2a254df
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml
@@ -0,0 +1,175 @@
+<?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"/>
+
+ <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..fbce0e8
--- /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..522337e
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/res/values/strings.xml
@@ -0,0 +1,30 @@
+<?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="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..735a327
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.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 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(": ");
+ sb.append(event.getAtom().getPushedCase().toString()).append("\n");
+ }
+ }
+
+ 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..a72f72e
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
@@ -0,0 +1,556 @@
+/*
+ * 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.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;
+import com.android.os.StatsLog.ConfigMetricsReport;
+import com.android.os.StatsLog.ConfigMetricsReportList;
+import com.android.os.StatsLog.StatsdStatsReport;
+import java.util.List;
+
+/**
+ * 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();
+ }
+ }
+ });
+
+ 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();
+ }
+
+ @Nullable
+ public StatsdStatsReport getMetadata() {
+ if (!statsdRunning()) {
+ return null;
+ }
+ if (mStatsManager != null) {
+ byte[] data = mStatsManager.getMetadata();
+ if (data != null) {
+ StatsdStatsReport report = null;
+ boolean good = false;
+ try {
+ return StatsdStatsReport.parseFrom(data);
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ Log.d(TAG, "Bad StatsdStatsReport");
+ }
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ public List<ConfigMetricsReport> getData() {
+ if (!statsdRunning()) {
+ return null;
+ }
+ if (mStatsManager != null) {
+ byte[] data = mStatsManager.getData(ConfigFactory.CONFIG_NAME);
+ if (data != null) {
+ ConfigMetricsReportList reports = null;
+ try {
+ reports = ConfigMetricsReportList.parseFrom(data);
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ Log.d(TAG, "Invalid data");
+ }
+ if (reports != null) {
+ return reports.getReportsList();
+ }
+ }
+ }
+ return null;
+ }
+
+ 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);
+
+ // Force a data flush by requesting data.
+ getData();
+
+ // 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 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..d9513a1
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java
@@ -0,0 +1,50 @@
+/*
+ * 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) {
+ 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..555e6dd
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java
@@ -0,0 +1,70 @@
+/*
+ * 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);
+ 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..22ba9c5
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java
@@ -0,0 +1,105 @@
+/*
+ * 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(LoadtestActivity loadtestActivity, 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));
+ mRecorders.add(new StatsdStatsRecorder(loadtestActivity, placebo, replication, bucketMins,
+ periodSecs, burst));
+ mRecorders.add(new ValidationRecorder(loadtestActivity, placebo, replication, bucketMins,
+ periodSecs, burst));
+ mAlarmMgr = (AlarmManager) loadtestActivity.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..5b5ba37
--- /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 mTimeAsString;
+ protected final String mColumnSuffix;
+
+ protected PerfDataRecorder(boolean placebo, int replication, long bucketMins, long periodSecs,
+ int burst) {
+ mTimeAsString = 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 + mTimeAsString + ".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/" + mTimeAsString);
+ 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/services/core/java/com/android/server/timezone/ClockHelper.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java
similarity index 67%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java
index 353728a..e000918 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java
@@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.statsd.loadtest;
-package com.android.server.timezone;
+import android.annotation.Nullable;
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
+public interface PerfParser {
- long currentTimestamp();
+ /**
+ * 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/statsd/tools/loadtest/src/com/android/statsd/loadtest/StatsdStatsRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/StatsdStatsRecorder.java
new file mode 100644
index 0000000..4ef5dc2
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/StatsdStatsRecorder.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.statsd.loadtest;
+
+import android.content.Context;
+import android.util.Log;
+import com.android.os.StatsLog.StatsdStatsReport;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StatsdStatsRecorder extends PerfDataRecorder {
+ private static final String TAG = "loadtest.StatsdStatsRecorder";
+
+ private final LoadtestActivity mLoadtestActivity;
+
+ public StatsdStatsRecorder(LoadtestActivity loadtestActivity, boolean placebo, int replication,
+ long bucketMins, long periodSecs, int burst) {
+ super(placebo, replication, bucketMins, periodSecs, burst);
+ mLoadtestActivity = loadtestActivity;
+ }
+
+ @Override
+ public void startRecording(Context context) {
+ // Nothing to do.
+ }
+
+ @Override
+ public void onAlarm(Context context) {
+ // Nothing to do.
+ }
+
+ @Override
+ public void stopRecording(Context context) {
+ StatsdStatsReport metadata = mLoadtestActivity.getMetadata();
+ if (metadata != null) {
+ int numConfigs = metadata.getConfigStatsCount();
+ StringBuilder sb = new StringBuilder();
+ StatsdStatsReport.ConfigStats configStats = metadata.getConfigStats(numConfigs - 1);
+ sb.append("metric_count,")
+ .append(configStats.getMetricCount() + "\n")
+ .append("condition_count,")
+ .append(configStats.getConditionCount() + "\n")
+ .append("matcher_count,")
+ .append(configStats.getMatcherCount() + "\n");
+ writeData(context, "statsdstats_", "", sb);
+ }
+ }
+}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java
new file mode 100644
index 0000000..4b614aa
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java
@@ -0,0 +1,95 @@
+/*
+ * 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.util.Log;
+import com.android.os.StatsLog.ConfigMetricsReport;
+import com.android.os.StatsLog.EventMetricData;
+import com.android.os.StatsLog.StatsLogReport;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Checks the correctness of the stats.
+ */
+public class ValidationRecorder extends PerfDataRecorder {
+ private static final String TAG = "loadtest.ValidationRecorder";
+
+ private final LoadtestActivity mLoadtestActivity;
+
+ public ValidationRecorder(LoadtestActivity loadtestActivity, boolean placebo, int replication,
+ long bucketMins, long periodSecs, int burst) {
+ super(placebo, replication, bucketMins, periodSecs, burst);
+ mLoadtestActivity = loadtestActivity;
+ }
+
+ @Override
+ public void startRecording(Context context) {
+ // Nothing to do.
+ }
+
+ @Override
+ public void onAlarm(Context context) {
+ validateData();
+ }
+
+ @Override
+ public void stopRecording(Context context) {
+ validateData();
+ }
+
+ private void validateData() {
+ List<ConfigMetricsReport> reports = mLoadtestActivity.getData();
+ if (reports != null) {
+ Log.d(TAG, "GOT DATA");
+ for (ConfigMetricsReport report : reports) {
+ for (StatsLogReport logReport : report.getMetricsList()) {
+ if (!logReport.hasMetricName()) {
+ Log.e(TAG, "Metric missing name.");
+ continue;
+ }
+ String metricName = logReport.getMetricName();
+ if (metricName.startsWith("EVENT_BATTERY_LEVEL_CHANGES_WHILE_SCREEN_IS_ON_")) {
+ validateEventBatteryLevelChangesWhileScreenIsOn(logReport);
+ continue;
+ }
+ if (metricName.startsWith("EVENT_BATTERY_LEVEL_CHANGES_")) {
+ validateEventBatteryLevelChanges(logReport);
+ continue;
+ }
+ }
+ }
+ }
+ }
+
+ private void validateEventBatteryLevelChanges(StatsLogReport logReport) {
+ Log.d(TAG, "Validating " + logReport.getMetricName());
+ if (logReport.hasEventMetrics()) {
+ Log.d(TAG, "Num events captured: " + logReport.getEventMetrics().getDataCount());
+ for (EventMetricData data : logReport.getEventMetrics().getDataList()) {
+ Log.d(TAG, " Event : " + data.getAtom());
+ }
+ } else {
+ Log.d(TAG, "Metric is invalid");
+ }
+ }
+
+ private void validateEventBatteryLevelChangesWhileScreenIsOn(StatsLogReport logReport) {
+ Log.d(TAG, "Validating " + logReport.getMetricName());
+ }
+}
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..62a2865 100644
--- a/cmds/uiautomator/library/Android.mk
+++ b/cmds/uiautomator/library/Android.mk
@@ -28,15 +28,15 @@
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)
###############################################
# Generate the stub source files
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(uiautomator.core_src_files)
-LOCAL_JAVA_LIBRARIES := $(uiautomator.core_java_libraries) legacy-android-test
+LOCAL_JAVA_LIBRARIES := $(uiautomator.core_java_libraries) android.test.base
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/core-src \
$(LOCAL_PATH)/testrunner-src
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/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 8824643..97dcb90 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -391,8 +391,12 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({SHOW_MODE_AUTO, SHOW_MODE_HIDDEN})
- public @interface SoftKeyboardShowMode {};
+ @IntDef(prefix = { "SHOW_MODE_" }, value = {
+ SHOW_MODE_AUTO,
+ SHOW_MODE_HIDDEN
+ })
+ public @interface SoftKeyboardShowMode {}
+
public static final int SHOW_MODE_AUTO = 0;
public static final int SHOW_MODE_HIDDEN = 1;
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 7a1931718..037aeb0 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -35,23 +35,23 @@
void setServiceInfo(in AccessibilityServiceInfo info);
- boolean findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
+ String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
long accessibilityNodeId, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
in Bundle arguments);
- boolean findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId,
+ String[] findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId,
String text, int interactionId, IAccessibilityInteractionConnectionCallback callback,
long threadId);
- boolean findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
+ String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
long accessibilityNodeId, String viewId, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long threadId);
- boolean findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType,
+ String[] findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType,
int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId);
- boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction,
+ String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction,
int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId);
boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId,
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index bd9c9fa..782733f 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -290,8 +290,13 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({VISIBILITY_UNDEFINED, VISIBILITY_VISIBLE, VISIBILITY_USER_MANAGED_VISIBLE,
- VISIBILITY_NOT_VISIBLE, VISIBILITY_USER_MANAGED_NOT_VISIBLE})
+ @IntDef(prefix = { "VISIBILITY_" }, value = {
+ VISIBILITY_UNDEFINED,
+ VISIBILITY_VISIBLE,
+ VISIBILITY_USER_MANAGED_VISIBLE,
+ VISIBILITY_NOT_VISIBLE,
+ VISIBILITY_USER_MANAGED_NOT_VISIBLE
+ })
public @interface AccountVisibility {
}
diff --git a/core/java/android/annotation/CallbackExecutor.java b/core/java/android/annotation/CallbackExecutor.java
new file mode 100644
index 0000000..5671a3d
--- /dev/null
+++ b/core/java/android/annotation/CallbackExecutor.java
@@ -0,0 +1,41 @@
+/*
+ * 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.annotation;
+
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.content.Context;
+import android.os.AsyncTask;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.util.concurrent.Executor;
+
+/**
+ * @paramDoc Callback and listener events are dispatched through this
+ * {@link Executor}, providing an easy way to control which thread is
+ * used. To dispatch events through the main thread of your
+ * application, you can use {@link Context#getMainExecutor()}. To
+ * dispatch events through a shared thread pool, you can use
+ * {@link AsyncTask#THREAD_POOL_EXECUTOR}.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target(PARAMETER)
+public @interface CallbackExecutor {
+}
diff --git a/core/java/android/annotation/Condemned.java b/core/java/android/annotation/Condemned.java
new file mode 100644
index 0000000..186409b
--- /dev/null
+++ b/core/java/android/annotation/Condemned.java
@@ -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.
+ */
+
+package android.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * A program element annotated @Condemned is one that programmers are
+ * blocked from using, typically because it's about to be completely destroyed.
+ * <p>
+ * This is a stronger version of @Deprecated, and it's typically used to
+ * mark APIs that only existed temporarily in a preview SDK, and which only
+ * continue to exist temporarily to support binary compatibility.
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
+public @interface Condemned {
+}
diff --git a/core/java/android/annotation/IntDef.java b/core/java/android/annotation/IntDef.java
index 3f9064e..f84a676 100644
--- a/core/java/android/annotation/IntDef.java
+++ b/core/java/android/annotation/IntDef.java
@@ -52,10 +52,12 @@
@Target({ANNOTATION_TYPE})
public @interface IntDef {
/** Defines the constant prefix for this element */
- String[] prefix() default "";
+ String[] prefix() default {};
+ /** Defines the constant suffix for this element */
+ String[] suffix() default {};
/** Defines the allowed constants for this element */
- long[] value() default {};
+ int[] value() default {};
/** Defines whether the constants can be used as a flag, or just as an enum (the default) */
boolean flag() default false;
diff --git a/core/java/android/annotation/LongDef.java b/core/java/android/annotation/LongDef.java
new file mode 100644
index 0000000..8723eef8
--- /dev/null
+++ b/core/java/android/annotation/LongDef.java
@@ -0,0 +1,62 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated long element represents
+ * a logical type and that its value should be one of the explicitly
+ * named constants. If the {@link #flag()} attribute is set to true,
+ * multiple constants can be combined.
+ * <p>
+ * <pre><code>
+ * @Retention(SOURCE)
+ * @LongDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
+ * public @interface NavigationMode {}
+ * public static final long NAVIGATION_MODE_STANDARD = 0;
+ * public static final long NAVIGATION_MODE_LIST = 1;
+ * public static final long NAVIGATION_MODE_TABS = 2;
+ * ...
+ * public abstract void setNavigationMode(@NavigationMode long mode);
+ * @NavigationMode
+ * public abstract long getNavigationMode();
+ * </code></pre>
+ * For a flag, set the flag attribute:
+ * <pre><code>
+ * @LongDef(
+ * flag = true,
+ * value = {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
+ * </code></pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({ANNOTATION_TYPE})
+public @interface LongDef {
+ /** Defines the constant prefix for this element */
+ String[] prefix() default "";
+
+ /** Defines the allowed constants for this element */
+ long[] value() default {};
+
+ /** Defines whether the constants can be used as a flag, or just as an enum (the default) */
+ boolean flag() default false;
+}
diff --git a/core/java/android/annotation/StringDef.java b/core/java/android/annotation/StringDef.java
index d5157c3..a37535b 100644
--- a/core/java/android/annotation/StringDef.java
+++ b/core/java/android/annotation/StringDef.java
@@ -46,6 +46,11 @@
@Retention(SOURCE)
@Target({ANNOTATION_TYPE})
public @interface StringDef {
+ /** Defines the constant prefix for this element */
+ String[] prefix() default {};
+ /** Defines the constant suffix for this element */
+ String[] suffix() default {};
+
/** Defines the allowed constants for this element */
String[] value() default {};
}
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 0e8326d..04ff48c 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -95,7 +95,11 @@
public abstract class ActionBar {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
+ @IntDef(prefix = { "NAVIGATION_MODE_" }, value = {
+ NAVIGATION_MODE_STANDARD,
+ NAVIGATION_MODE_LIST,
+ NAVIGATION_MODE_TABS
+ })
public @interface NavigationMode {}
/**
@@ -139,15 +143,14 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- value = {
- DISPLAY_USE_LOGO,
- DISPLAY_SHOW_HOME,
- DISPLAY_HOME_AS_UP,
- DISPLAY_SHOW_TITLE,
- DISPLAY_SHOW_CUSTOM,
- DISPLAY_TITLE_MULTIPLE_LINES
- })
+ @IntDef(flag = true, prefix = { "DISPLAY_" }, value = {
+ DISPLAY_USE_LOGO,
+ DISPLAY_SHOW_HOME,
+ DISPLAY_HOME_AS_UP,
+ DISPLAY_SHOW_TITLE,
+ DISPLAY_SHOW_CUSTOM,
+ DISPLAY_TITLE_MULTIPLE_LINES
+ })
public @interface DisplayOptions {}
/**
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..847082a 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -175,7 +175,7 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
+ @IntDef(prefix = { "BUGREPORT_OPTION_" }, value = {
BUGREPORT_OPTION_FULL,
BUGREPORT_OPTION_INTERACTIVE,
BUGREPORT_OPTION_REMOTE,
@@ -533,10 +533,10 @@
// to frameworks/base/core/proto/android/app/activitymanager.proto and the following method must
// be updated to correctly map between them.
/**
- * Maps ActivityManager.PROCESS_STATE_ values to ActivityManagerProto.ProcessState enum.
+ * Maps ActivityManager.PROCESS_STATE_ values to ProcessState enum.
*
* @param amInt a process state of the form ActivityManager.PROCESS_STATE_
- * @return the value of the corresponding android.app.ActivityManagerProto's ProcessState enum.
+ * @return the value of the corresponding ActivityManager's ProcessState enum.
* @hide
*/
public static final int processStateAmToProto(int amInt) {
@@ -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();
}
@@ -2611,7 +2613,7 @@
Manifest.permission.ACCESS_INSTANT_APPS})
public boolean clearApplicationUserData(String packageName, IPackageDataObserver observer) {
try {
- return getService().clearApplicationUserData(packageName,
+ return getService().clearApplicationUserData(packageName, false,
observer, UserHandle.myUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -2942,10 +2944,10 @@
/**
* Constant for {@link #importance}: This process is running an
* application that can not save its state, and thus can't be killed
- * while in the background.
- * @hide
+ * while in the background. This will be used with apps that have
+ * {@link android.R.attr#cantSaveState} set on their application tag.
*/
- public static final int IMPORTANCE_CANT_SAVE_STATE= 270;
+ public static final int IMPORTANCE_CANT_SAVE_STATE = 270;
/**
* Constant for {@link #importance}: This process is contains services
@@ -2993,7 +2995,7 @@
return IMPORTANCE_CACHED;
} else if (procState >= PROCESS_STATE_SERVICE) {
return IMPORTANCE_SERVICE;
- } else if (procState > PROCESS_STATE_HEAVY_WEIGHT) {
+ } else if (procState == PROCESS_STATE_HEAVY_WEIGHT) {
return IMPORTANCE_CANT_SAVE_STATE;
} else if (procState >= PROCESS_STATE_TRANSIENT_BACKGROUND) {
return IMPORTANCE_PERCEPTIBLE;
@@ -3049,7 +3051,7 @@
return PROCESS_STATE_HOME;
} else if (importance >= IMPORTANCE_SERVICE) {
return PROCESS_STATE_SERVICE;
- } else if (importance > IMPORTANCE_CANT_SAVE_STATE) {
+ } else if (importance == IMPORTANCE_CANT_SAVE_STATE) {
return PROCESS_STATE_HEAVY_WEIGHT;
} else if (importance >= IMPORTANCE_PERCEPTIBLE) {
return PROCESS_STATE_TRANSIENT_BACKGROUND;
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index d7efa91..6666fcc 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -261,6 +261,11 @@
public abstract void notifyNetworkPolicyRulesUpdated(int uid, long procStateSeq);
/**
+ * Called after the voice interaction service has changed.
+ */
+ public abstract void notifyActiveVoiceInteractionServiceChanged(ComponentName component);
+
+ /**
* Called after virtual display Id is updated by
* {@link com.android.server.vr.Vr2dDisplay} with a specific
* {@param vr2dDisplayId}.
@@ -299,4 +304,9 @@
* @return true if runtime was restarted, false if it's normal boot
*/
public abstract boolean isRuntimeRestarted();
+
+ /**
+ * Returns {@code true} if {@code uid} is running an activity from {@code packageName}.
+ */
+ public abstract boolean hasRunningActivity(int uid, @Nullable String packageName);
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ffd012d..ef446c2 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,8 +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;
@@ -69,6 +80,7 @@
import android.os.Environment;
import android.os.GraphicsEnvironment;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.LocaleList;
import android.os.Looper;
@@ -84,7 +96,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;
@@ -102,12 +113,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;
@@ -121,6 +132,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;
@@ -128,9 +140,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;
@@ -161,6 +173,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.TimeZone;
+import java.util.concurrent.Executor;
final class RemoteServiceException extends AndroidRuntimeException {
public RemoteServiceException(String msg) {
@@ -188,7 +201,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;
@@ -204,10 +217,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;
@@ -235,6 +244,7 @@
final ApplicationThread mAppThread = new ApplicationThread();
final Looper mLooper = Looper.myLooper();
final H mH = new H();
+ final Executor mExecutor = new HandlerExecutor(mH);
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
// List of new activities (via ActivityRecord.nextIdle) that should
// be reported when next we idle.
@@ -287,12 +297,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;
@@ -340,8 +346,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;
@@ -353,6 +360,7 @@
Activity parent;
String embeddedID;
Activity.NonConfigurationInstances lastNonConfigurationInstances;
+ // TODO(lifecycler): Use mLifecycleState instead.
boolean paused;
boolean stopped;
boolean hideForNow;
@@ -369,13 +377,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;
@@ -383,15 +391,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;
@@ -408,6 +443,38 @@
};
}
+ /** 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
@@ -1313,13 +1380,6 @@
mAppThread.updateProcessState(processState, fromIpc);
}
- @Override
- public int getLifecycleSeq() {
- synchronized (mResourcesManager) {
- return mLifecycleSeq++;
- }
- }
-
class H extends Handler {
public static final int BIND_APPLICATION = 110;
public static final int EXIT_APPLICATION = 111;
@@ -1584,7 +1644,7 @@
(String[]) ((SomeArgs) msg.obj).arg2);
break;
case EXECUTE_TRANSACTION:
- ((ClientTransaction) msg.obj).execute(ActivityThread.this);
+ mTransactionExecutor.execute(((ClientTransaction) msg.obj));
break;
}
Object obj = msg.obj;
@@ -1794,6 +1854,7 @@
registerPackage);
}
+ @Override
public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
CompatibilityInfo compatInfo) {
return getPackageInfo(ai, compatInfo, null, false, true, false);
@@ -1885,6 +1946,10 @@
return mLooper;
}
+ public Executor getExecutor() {
+ return mExecutor;
+ }
+
public Application getApplication() {
return mInitialApplication;
}
@@ -2259,6 +2324,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) {
@@ -2316,13 +2542,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) {
@@ -2330,8 +2564,8 @@
+ " req=" + requestCode + " res=" + resultCode + " data=" + data);
ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
list.add(new ResultInfo(id, requestCode, resultCode, data));
- final ClientTransaction clientTransaction = new ClientTransaction(mAppThread, token);
- clientTransaction.addCallback(new ActivityResultItem(list));
+ final ClientTransaction clientTransaction = ClientTransaction.obtain(mAppThread, token);
+ clientTransaction.addCallback(ActivityResultItem.obtain(list));
try {
mAppThread.scheduleTransaction(clientTransaction);
} catch (RemoteException e) {
@@ -2390,9 +2624,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,
@@ -2462,9 +2695,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;
@@ -2485,37 +2715,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);
@@ -2533,6 +2734,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
@@ -2579,38 +2834,12 @@
return appContext;
}
+ /**
+ * Extended implementation of activity launch. Used when server requests a launch or relaunch.
+ */
@Override
- public void handleLaunchActivity(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 notResumed, boolean isForward, ProfilerInfo profilerInfo) {
- 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;
- r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);
- handleLaunchActivity(r, null /* customIntent */, "LAUNCH_ACTIVITY");
- }
-
- private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
+ 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();
@@ -2633,44 +2862,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) {
@@ -2946,7 +3159,8 @@
data.intent.setExtrasClassLoader(cl);
data.intent.prepareToEnterProcess();
data.setExtrasClassLoader(cl);
- receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
+ receiver = packageInfo.getAppFactory()
+ .instantiateReceiver(cl, data.info.name, data.intent);
} catch (Exception e) {
if (DEBUG_BROADCAST) Slog.i(TAG,
"Finishing failed broadcast to " + data.intent.getComponent());
@@ -3101,7 +3315,8 @@
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
- service = (Service) cl.loadClass(data.info.name).newInstance();
+ service = packageInfo.getAppFactory()
+ .instantiateService(cl, data.info.name, data.intent);
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
@@ -3314,8 +3529,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);
@@ -3355,10 +3569,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(
@@ -3390,19 +3603,14 @@
@Override
public 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;
- }
-
+ 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;
@@ -3514,16 +3722,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.
@@ -3594,21 +3792,17 @@
}
@Override
- public void handlePauseActivity(IBinder token, boolean finished,
- boolean userLeaving, int configChanges, boolean dontReport, int seq) {
+ 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()) {
@@ -3632,13 +3826,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.
@@ -3672,6 +3868,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;
}
@@ -3698,7 +3906,7 @@
+ safeToComponentShortString(r.intent) + ": " + e.toString(), e);
}
}
- r.paused = true;
+ r.setState(ON_PAUSE);
}
final void performStopActivity(IBinder token, boolean saveState, String reason) {
@@ -3706,37 +3914,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;
@@ -3767,8 +3944,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) {
@@ -3793,7 +3970,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(
@@ -3823,7 +4000,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);
}
@@ -3859,15 +4036,13 @@
}
@Override
- public void handleStopActivity(IBinder token, boolean show, int configChanges, int seq) {
- ActivityClientRecord r = mActivities.get(token);
- if (!checkAndUpdateLifecycleSeq(seq, r, "stopActivity")) {
- return;
- }
+ 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
@@ -3880,37 +4055,32 @@
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);
+ }
}
}
@@ -3930,8 +4100,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(
@@ -3969,7 +4139,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");
}
@@ -3987,8 +4157,8 @@
}
} else {
if (r.stopped && r.activity.mVisibleFromServer) {
- r.activity.performRestart();
- r.stopped = false;
+ r.activity.performRestart(true /* start */);
+ r.setState(ON_START);
}
}
}
@@ -4105,11 +4275,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;
@@ -4136,7 +4303,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");
}
@@ -4173,6 +4340,7 @@
+ ": " + e.toString(), e);
}
}
+ r.setState(ON_DESTROY);
}
mActivities.remove(token);
StrictMode.decrementExpectedActivityCount(activityClass);
@@ -4333,10 +4501,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) {
@@ -4381,12 +4546,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
@@ -4427,9 +4586,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;
@@ -4455,7 +4611,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);
@@ -4485,7 +4642,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 {
@@ -5449,7 +5614,16 @@
// Continue loading instrumentation.
if (ii != null) {
- final ApplicationInfo instrApp = new ApplicationInfo();
+ ApplicationInfo instrApp;
+ try {
+ instrApp = getPackageManager().getApplicationInfo(ii.packageName, 0,
+ UserHandle.myUserId());
+ } catch (RemoteException e) {
+ instrApp = null;
+ }
+ if (instrApp == null) {
+ instrApp = new ApplicationInfo();
+ }
ii.copyTo(instrApp);
instrApp.initForUser(UserHandle.myUserId());
final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
@@ -5479,6 +5653,7 @@
}
} else {
mInstrumentation = new Instrumentation();
+ mInstrumentation.basicInit(this);
}
if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
@@ -6010,8 +6185,13 @@
try {
final java.lang.ClassLoader cl = c.getClassLoader();
- localProvider = (ContentProvider)cl.
- loadClass(info.name).newInstance();
+ LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
+ if (packageInfo == null) {
+ // System startup case.
+ packageInfo = getSystemContext().mPackageInfo;
+ }
+ localProvider = packageInfo.getAppFactory()
+ .instantiateProvider(cl, info.name);
provider = localProvider.getIContentProvider();
if (provider == null) {
Slog.e(TAG, "Failed to instantiate class " +
@@ -6157,6 +6337,7 @@
UserHandle.myUserId());
try {
mInstrumentation = new Instrumentation();
+ mInstrumentation.basicInit(this);
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 55f9e28..382719b 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -568,9 +568,21 @@
}
/**
- * Schedule an alarm that represents an alarm clock.
+ * Schedule an alarm that represents an alarm clock, which will be used to notify the user
+ * when it goes off. The expectation is that when this alarm triggers, the application will
+ * further wake up the device to tell the user about the alarm -- turning on the screen,
+ * playing a sound, vibrating, etc. As such, the system will typically also use the
+ * information supplied here to tell the user about this upcoming alarm if appropriate.
*
- * The system may choose to display information about this alarm to the user.
+ * <p>Due to the nature of this kind of alarm, similar to {@link #setExactAndAllowWhileIdle},
+ * these alarms will be allowed to trigger even if the system is in a low-power idle
+ * (a.k.a. doze) mode. The system may also do some prep-work when it sees that such an
+ * alarm coming up, to reduce the amount of background work that could happen if this
+ * causes the device to fully wake up -- this is to avoid situations such as a large number
+ * of devices having an alarm set at the same time in the morning, all waking up at that
+ * time and suddenly swamping the network with pending background work. As such, these
+ * types of alarms can be extremely expensive on battery use and should only be used for
+ * their intended purpose.</p>
*
* <p>
* This method is like {@link #setExact(int, long, PendingIntent)}, but implies
@@ -783,9 +795,9 @@
/**
* Like {@link #set(int, long, PendingIntent)}, but this alarm will be allowed to execute
- * even when the system is in low-power idle modes. This type of alarm must <b>only</b>
- * be used for situations where it is actually required that the alarm go off while in
- * idle -- a reasonable example would be for a calendar notification that should make a
+ * even when the system is in low-power idle (a.k.a. doze) modes. This type of alarm must
+ * <b>only</b> be used for situations where it is actually required that the alarm go off while
+ * in idle -- a reasonable example would be for a calendar notification that should make a
* sound so the user is aware of it. When the alarm is dispatched, the app will also be
* added to the system's temporary whitelist for approximately 10 seconds to allow that
* application to acquire further wake locks in which to complete its work.</p>
diff --git a/core/java/android/app/AppComponentFactory.java b/core/java/android/app/AppComponentFactory.java
new file mode 100644
index 0000000..4df7379
--- /dev/null
+++ b/core/java/android/app/AppComponentFactory.java
@@ -0,0 +1,112 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.ContentProvider;
+import android.content.Intent;
+
+/**
+ * Interface used to control the instantiation of manifest elements.
+ *
+ * @see #instantiateApplication
+ * @see #instantiateActivity
+ * @see #instantiateService
+ * @see #instantiateReceiver
+ * @see #instantiateProvider
+ */
+public class AppComponentFactory {
+
+ /**
+ * Allows application to override the creation of the application object. This can be used to
+ * perform things such as dependency injection or class loader changes to these
+ * classes.
+ *
+ * @param cl The default classloader to use for instantiation.
+ * @param className The class to be instantiated.
+ */
+ public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
+ @NonNull String className)
+ throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ return (Application) cl.loadClass(className).newInstance();
+ }
+
+ /**
+ * Allows application to override the creation of activities. This can be used to
+ * perform things such as dependency injection or class loader changes to these
+ * classes.
+ *
+ * @param cl The default classloader to use for instantiation.
+ * @param className The class to be instantiated.
+ * @param intent Intent creating the class.
+ */
+ public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className,
+ @Nullable Intent intent)
+ throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ return (Activity) cl.loadClass(className).newInstance();
+ }
+
+ /**
+ * Allows application to override the creation of receivers. This can be used to
+ * perform things such as dependency injection or class loader changes to these
+ * classes.
+ *
+ * @param cl The default classloader to use for instantiation.
+ * @param className The class to be instantiated.
+ * @param intent Intent creating the class.
+ */
+ public @NonNull BroadcastReceiver instantiateReceiver(@NonNull ClassLoader cl,
+ @NonNull String className, @Nullable Intent intent)
+ throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ return (BroadcastReceiver) cl.loadClass(className).newInstance();
+ }
+
+ /**
+ * Allows application to override the creation of services. This can be used to
+ * perform things such as dependency injection or class loader changes to these
+ * classes.
+ *
+ * @param cl The default classloader to use for instantiation.
+ * @param className The class to be instantiated.
+ * @param intent Intent creating the class.
+ */
+ public @NonNull Service instantiateService(@NonNull ClassLoader cl,
+ @NonNull String className, @Nullable Intent intent)
+ throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ return (Service) cl.loadClass(className).newInstance();
+ }
+
+ /**
+ * Allows application to override the creation of providers. This can be used to
+ * perform things such as dependency injection or class loader changes to these
+ * classes.
+ *
+ * @param cl The default classloader to use for instantiation.
+ * @param className The class to be instantiated.
+ */
+ public @NonNull ContentProvider instantiateProvider(@NonNull ClassLoader cl,
+ @NonNull String className)
+ throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ return (ContentProvider) cl.loadClass(className).newInstance();
+ }
+
+ /**
+ * @hide
+ */
+ public static AppComponentFactory DEFAULT = new AppComponentFactory();
+}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index b6fb120..c1a5104 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -256,8 +256,10 @@
public static final int OP_RUN_ANY_IN_BACKGROUND = 70;
/** @hide Change Wi-Fi connectivity state */
public static final int OP_CHANGE_WIFI_STATE = 71;
+ /** @hide Request package deletion through package installer */
+ public static final int OP_REQUEST_DELETE_PACKAGES = 72;
/** @hide */
- public static final int _NUM_OP = 72;
+ public static final int _NUM_OP = 73;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -410,6 +412,7 @@
OP_CAMERA,
// Body sensors
OP_BODY_SENSORS,
+ OP_REQUEST_DELETE_PACKAGES,
// APPOP PERMISSIONS
OP_ACCESS_NOTIFICATIONS,
@@ -499,6 +502,7 @@
OP_ANSWER_PHONE_CALLS,
OP_RUN_ANY_IN_BACKGROUND,
OP_CHANGE_WIFI_STATE,
+ OP_REQUEST_DELETE_PACKAGES,
};
/**
@@ -578,6 +582,7 @@
OPSTR_ANSWER_PHONE_CALLS,
null, // OP_RUN_ANY_IN_BACKGROUND
null, // OP_CHANGE_WIFI_STATE
+ null, // OP_REQUEST_DELETE_PACKAGES
};
/**
@@ -657,6 +662,7 @@
"ANSWER_PHONE_CALLS",
"RUN_ANY_IN_BACKGROUND",
"CHANGE_WIFI_STATE",
+ "REQUEST_DELETE_PACKAGES",
};
/**
@@ -736,6 +742,7 @@
Manifest.permission.ANSWER_PHONE_CALLS,
null, // no permission for OP_RUN_ANY_IN_BACKGROUND
Manifest.permission.CHANGE_WIFI_STATE,
+ Manifest.permission.REQUEST_DELETE_PACKAGES,
};
/**
@@ -816,6 +823,7 @@
null, // ANSWER_PHONE_CALLS
null, // OP_RUN_ANY_IN_BACKGROUND
null, // OP_CHANGE_WIFI_STATE
+ null, // REQUEST_DELETE_PACKAGES
};
/**
@@ -895,6 +903,7 @@
false, // ANSWER_PHONE_CALLS
false, // OP_RUN_ANY_IN_BACKGROUND
false, // OP_CHANGE_WIFI_STATE
+ false, // OP_REQUEST_DELETE_PACKAGES
};
/**
@@ -973,6 +982,7 @@
AppOpsManager.MODE_ALLOWED, // ANSWER_PHONE_CALLS
AppOpsManager.MODE_ALLOWED, // OP_RUN_ANY_IN_BACKGROUND
AppOpsManager.MODE_ALLOWED, // OP_CHANGE_WIFI_STATE
+ AppOpsManager.MODE_ALLOWED, // REQUEST_DELETE_PACKAGES
};
/**
@@ -1055,6 +1065,7 @@
false, // ANSWER_PHONE_CALLS
false, // OP_RUN_ANY_IN_BACKGROUND
false, // OP_CHANGE_WIFI_STATE
+ false, // OP_REQUEST_DELETE_PACKAGES
};
/**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 005b7c3..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<>();
@@ -2750,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
index f7f4c71..ef66af0 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -16,15 +16,12 @@
package android.app;
import android.app.servertransaction.ClientTransaction;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
+import android.app.servertransaction.PendingTransactionActions;
+import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
-import android.os.Bundle;
import android.os.IBinder;
-import android.os.PersistableBundle;
-import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.ReferrerIntent;
import java.util.List;
@@ -40,7 +37,7 @@
/** Prepare and schedule transaction for execution. */
void scheduleTransaction(ClientTransaction transaction) {
- transaction.prepare(this);
+ transaction.preExecute(this);
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
@@ -50,9 +47,6 @@
// Prepare phase related logic and handlers. Methods that inform about about pending changes or
// do other internal bookkeeping.
- /** Get current lifecycle request number to maintain correct ordering. */
- public abstract int getLifecycleSeq();
-
/** Set pending config in case it will be updated by other transaction item. */
public abstract void updatePendingConfiguration(Configuration config);
@@ -69,15 +63,21 @@
/** Pause the activity. */
public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
- int configChanges, boolean dontReport, int seq);
+ int configChanges, boolean dontReport, PendingTransactionActions pendingActions);
/** Resume the activity. */
public abstract void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
- boolean reallyResume, int seq, String reason);
+ String reason);
/** Stop the activity. */
public abstract void handleStopActivity(IBinder token, boolean show, int configChanges,
- int seq);
+ 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,
@@ -102,13 +102,23 @@
public abstract void handleWindowVisibility(IBinder token, boolean show);
/** Perform activity launch. */
- public abstract void handleLaunchActivity(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 notResumed, boolean isForward,
- ProfilerInfo profilerInfo);
+ 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 b0d020a..a2de0f4 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -90,6 +90,7 @@
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Objects;
+import java.util.concurrent.Executor;
class ReceiverRestrictedContext extends ContextWrapper {
ReceiverRestrictedContext(Context base) {
@@ -250,6 +251,11 @@
}
@Override
+ public Executor getMainExecutor() {
+ return mMainThread.getExecutor();
+ }
+
+ @Override
public Context getApplicationContext() {
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 0f4a7fb..1103649 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -182,7 +182,12 @@
public static final int TRANSIT_FRAGMENT_FADE = 3 | TRANSIT_ENTER_MASK;
/** @hide */
- @IntDef({TRANSIT_NONE, TRANSIT_FRAGMENT_OPEN, TRANSIT_FRAGMENT_CLOSE, TRANSIT_FRAGMENT_FADE})
+ @IntDef(prefix = { "TRANSIT_" }, value = {
+ TRANSIT_NONE,
+ TRANSIT_FRAGMENT_OPEN,
+ TRANSIT_FRAGMENT_CLOSE,
+ TRANSIT_FRAGMENT_FADE
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Transit {}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 2d6308c..85bf6aa 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -207,7 +207,7 @@
boolean moveActivityTaskToBack(in IBinder token, boolean nonRoot);
void getMemoryInfo(out ActivityManager.MemoryInfo outInfo);
List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState();
- boolean clearApplicationUserData(in String packageName,
+ boolean clearApplicationUserData(in String packageName, boolean keepState,
in IPackageDataObserver observer, int userId);
void forceStopPackage(in String packageName, int userId);
boolean killPids(in int[] pids, in String reason, boolean secure);
@@ -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/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/Instrumentation.java b/core/java/android/app/Instrumentation.java
index d49e11f..490b2bf 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1114,7 +1114,10 @@
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
- return newApplication(cl.loadClass(className), context);
+ Application app = getFactory(context.getPackageName())
+ .instantiateApplication(cl, className);
+ app.attach(context);
+ return app;
}
/**
@@ -1201,7 +1204,15 @@
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
- return (Activity)cl.loadClass(className).newInstance();
+ String pkg = intent.getComponent().getPackageName();
+ return getFactory(pkg).instantiateActivity(cl, className, intent);
+ }
+
+ private AppComponentFactory getFactory(String pkg) {
+ LoadedApk apk = mThread.peekPackageInfo(pkg, true);
+ // This is in the case of starting up "android".
+ if (apk == null) apk = mThread.getSystemContext().mPackageInfo;
+ return apk.getAppFactory();
}
private void prePerformCreate(Activity activity) {
@@ -1950,6 +1961,14 @@
mUiAutomationConnection = uiAutomationConnection;
}
+ /**
+ * Only sets the ActivityThread up, keeps everything else null because app is not being
+ * instrumented.
+ */
+ final void basicInit(ActivityThread thread) {
+ mThread = thread;
+ }
+
/** @hide */
public static void checkStartActivityResult(int res, Object intent) {
if (!ActivityManager.isStartResultFatalError(res)) {
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..ab00a7d 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -125,6 +125,7 @@
= new ArrayMap<>();
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices
= new ArrayMap<>();
+ private AppComponentFactory mAppComponentFactory;
Application getApplication() {
return mApplication;
@@ -148,6 +149,7 @@
mIncludeCode = includeCode;
mRegisterPackage = registerPackage;
mDisplayAdjustments.setCompatibilityInfo(compatInfo);
+ mAppComponentFactory = createAppFactory(mApplicationInfo, mBaseClassLoader);
}
private static ApplicationInfo adjustNativeLibraryPaths(ApplicationInfo info) {
@@ -203,6 +205,7 @@
mRegisterPackage = false;
mClassLoader = ClassLoader.getSystemClassLoader();
mResources = Resources.getSystem();
+ mAppComponentFactory = createAppFactory(mApplicationInfo, mClassLoader);
}
/**
@@ -212,6 +215,23 @@
assert info.packageName.equals("android");
mApplicationInfo = info;
mClassLoader = classLoader;
+ mAppComponentFactory = createAppFactory(info, classLoader);
+ }
+
+ private AppComponentFactory createAppFactory(ApplicationInfo appInfo, ClassLoader cl) {
+ if (appInfo.appComponentFactory != null) {
+ try {
+ return (AppComponentFactory) cl.loadClass(appInfo.appComponentFactory)
+ .newInstance();
+ } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
+ Slog.e(TAG, "Unable to instantiate appComponentFactory", e);
+ }
+ }
+ return AppComponentFactory.DEFAULT;
+ }
+
+ public AppComponentFactory getAppFactory() {
+ return mAppComponentFactory;
}
public String getPackageName() {
@@ -313,6 +333,7 @@
getClassLoader());
}
}
+ mAppComponentFactory = createAppFactory(aInfo, mClassLoader);
}
private void setApplicationInfo(ApplicationInfo aInfo) {
@@ -638,8 +659,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 +1667,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..705f9a0 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -577,7 +577,13 @@
public int flags;
/** @hide */
- @IntDef({PRIORITY_DEFAULT,PRIORITY_LOW,PRIORITY_MIN,PRIORITY_HIGH,PRIORITY_MAX})
+ @IntDef(prefix = { "PRIORITY_" }, value = {
+ PRIORITY_DEFAULT,
+ PRIORITY_LOW,
+ PRIORITY_MIN,
+ PRIORITY_HIGH,
+ PRIORITY_MAX
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Priority {}
@@ -1941,6 +1947,7 @@
mSortKey = parcel.readString();
extras = Bundle.setDefusable(parcel.readBundle(), true); // may be null
+ fixDuplicateExtras();
actions = parcel.createTypedArray(Action.CREATOR); // may be null
@@ -2389,6 +2396,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/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/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 23c4166..85a9be3 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -80,9 +80,14 @@
public static final int DISABLE2_MASK = DISABLE2_QUICK_SETTINGS | DISABLE2_SYSTEM_ICONS
| DISABLE2_NOTIFICATION_SHADE | DISABLE2_GLOBAL_ACTIONS;
- @IntDef(flag = true,
- value = {DISABLE2_NONE, DISABLE2_MASK, DISABLE2_QUICK_SETTINGS, DISABLE2_SYSTEM_ICONS,
- DISABLE2_NOTIFICATION_SHADE, DISABLE2_GLOBAL_ACTIONS})
+ @IntDef(flag = true, prefix = { "DISABLE2_" }, value = {
+ DISABLE2_NONE,
+ DISABLE2_MASK,
+ DISABLE2_QUICK_SETTINGS,
+ DISABLE2_SYSTEM_ICONS,
+ DISABLE2_NOTIFICATION_SHADE,
+ DISABLE2_GLOBAL_ACTIONS
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Disable2Flags {}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e48946f..495fd3c 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;
@@ -617,12 +618,13 @@
ConnectivityThread.getInstanceLooper());
}});
- registerService(Context.WIFI_RTT2_SERVICE, WifiRttManager.class,
+ registerService(Context.WIFI_RTT_RANGING_SERVICE, WifiRttManager.class,
new CachedServiceFetcher<WifiRttManager>() {
@Override
public WifiRttManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
- IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_RTT2_SERVICE);
+ IBinder b = ServiceManager.getServiceOrThrow(
+ Context.WIFI_RTT_RANGING_SERVICE);
IWifiRttManager service = IWifiRttManager.Stub.asInterface(b);
return new WifiRttManager(ctx.getOuterContext(), service);
}});
@@ -944,6 +946,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/UiModeManager.java b/core/java/android/app/UiModeManager.java
index bc61668..0da5e24 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -98,7 +98,11 @@
public static String ACTION_EXIT_DESK_MODE = "android.app.action.EXIT_DESK_MODE";
/** @hide */
- @IntDef({MODE_NIGHT_AUTO, MODE_NIGHT_NO, MODE_NIGHT_YES})
+ @IntDef(prefix = { "MODE_" }, value = {
+ MODE_NIGHT_AUTO,
+ MODE_NIGHT_NO,
+ MODE_NIGHT_YES
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface NightMode {}
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/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 081bd81..3829afb 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -176,7 +176,7 @@
// flags for which kind of wallpaper to act on
/** @hide */
- @IntDef(flag = true, value = {
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
FLAG_SYSTEM,
FLAG_LOCK
})
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 80399ae..085fc79 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -89,7 +89,7 @@
public static final int WINDOWING_MODE_FREEFORM = 5;
/** @hide */
- @IntDef({
+ @IntDef(prefix = { "WINDOWING_MODE_" }, value = {
WINDOWING_MODE_UNDEFINED,
WINDOWING_MODE_FULLSCREEN,
WINDOWING_MODE_PINNED,
@@ -115,7 +115,7 @@
public static final int ACTIVITY_TYPE_ASSISTANT = 4;
/** @hide */
- @IntDef({
+ @IntDef(prefix = { "ACTIVITY_TYPE_" }, value = {
ACTIVITY_TYPE_UNDEFINED,
ACTIVITY_TYPE_STANDARD,
ACTIVITY_TYPE_HOME,
@@ -138,13 +138,12 @@
public static final int WINDOW_CONFIG_ACTIVITY_TYPE = 1 << 3;
/** @hide */
- @IntDef(flag = true,
- value = {
- WINDOW_CONFIG_BOUNDS,
- WINDOW_CONFIG_APP_BOUNDS,
- WINDOW_CONFIG_WINDOWING_MODE,
- WINDOW_CONFIG_ACTIVITY_TYPE
- })
+ @IntDef(flag = true, prefix = { "WINDOW_CONFIG_" }, value = {
+ WINDOW_CONFIG_BOUNDS,
+ WINDOW_CONFIG_APP_BOUNDS,
+ WINDOW_CONFIG_WINDOWING_MODE,
+ WINDOW_CONFIG_ACTIVITY_TYPE
+ })
public @interface WindowConfig {}
public WindowConfiguration() {
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index d0d98c9..2e697ac 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -368,9 +368,9 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
- BUGREPORT_FAILURE_FAILED_COMPLETING,
- BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE
+ @IntDef(prefix = { "BUGREPORT_FAILURE_" }, value = {
+ BUGREPORT_FAILURE_FAILED_COMPLETING,
+ BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE
})
public @interface BugreportFailureCode {}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 0bca969..b1c17d5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16,7 +16,9 @@
package android.app.admin;
+import android.annotation.CallbackExecutor;
import android.annotation.ColorInt;
+import android.annotation.Condemned;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -49,6 +51,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.Process;
@@ -57,7 +60,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 +83,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;
@@ -88,6 +97,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.Executor;
/**
* Public interface for managing policies enforced on a device. Most clients of this class must be
@@ -1315,9 +1325,15 @@
public static final String DELEGATION_ENABLE_SYSTEM_APP = "delegation-enable-system-app";
/**
+ * Delegation for installing existing packages. This scope grants access to the
+ * {@link #installExistingPackage} API.
+ */
+ public static final String DELEGATION_INSTALL_EXISTING_PACKAGE =
+ "delegation-install-existing-package";
+
+ /**
* Delegation of management of uninstalled packages. This scope grants access to the
* {@code #setKeepUninstalledPackages} and {@code #getKeepUninstalledPackages} APIs.
- * @hide
*/
public static final String DELEGATION_KEEP_UNINSTALLED_PACKAGES =
"delegation-keep-uninstalled-packages";
@@ -1360,8 +1376,13 @@
/**
* @hide
*/
- @IntDef({STATE_USER_UNMANAGED, STATE_USER_SETUP_INCOMPLETE, STATE_USER_SETUP_COMPLETE,
- STATE_USER_SETUP_FINALIZED, STATE_USER_PROFILE_COMPLETE})
+ @IntDef(prefix = { "STATE_USER_" }, value = {
+ STATE_USER_UNMANAGED,
+ STATE_USER_SETUP_INCOMPLETE,
+ STATE_USER_SETUP_COMPLETE,
+ STATE_USER_SETUP_FINALIZED,
+ STATE_USER_PROFILE_COMPLETE
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface UserProvisioningState {}
@@ -1534,11 +1555,13 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({CODE_OK, CODE_HAS_DEVICE_OWNER, CODE_USER_HAS_PROFILE_OWNER, CODE_USER_NOT_RUNNING,
+ @IntDef(prefix = { "CODE_" }, value = {
+ CODE_OK, CODE_HAS_DEVICE_OWNER, CODE_USER_HAS_PROFILE_OWNER, CODE_USER_NOT_RUNNING,
CODE_USER_SETUP_COMPLETED, CODE_NOT_SYSTEM_USER, CODE_HAS_PAIRED,
CODE_MANAGED_USERS_NOT_SUPPORTED, CODE_SYSTEM_USER, CODE_CANNOT_ADD_MANAGED_PROFILE,
CODE_NOT_SYSTEM_USER_SPLIT, CODE_DEVICE_ADMIN_NOT_SUPPORTED,
- CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER, CODE_ADD_MANAGED_PROFILE_DISALLOWED})
+ CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER, CODE_ADD_MANAGED_PROFILE_DISALLOWED
+ })
public @interface ProvisioningPreCondition {}
/**
@@ -1620,11 +1643,15 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- value = {LOCK_TASK_FEATURE_NONE, LOCK_TASK_FEATURE_SYSTEM_INFO,
- LOCK_TASK_FEATURE_NOTIFICATIONS, LOCK_TASK_FEATURE_HOME,
- LOCK_TASK_FEATURE_RECENTS, LOCK_TASK_FEATURE_GLOBAL_ACTIONS,
- LOCK_TASK_FEATURE_KEYGUARD})
+ @IntDef(flag = true, prefix = { "LOCK_TASK_FEATURE_" }, value = {
+ LOCK_TASK_FEATURE_NONE,
+ LOCK_TASK_FEATURE_SYSTEM_INFO,
+ LOCK_TASK_FEATURE_NOTIFICATIONS,
+ LOCK_TASK_FEATURE_HOME,
+ LOCK_TASK_FEATURE_RECENTS,
+ LOCK_TASK_FEATURE_GLOBAL_ACTIONS,
+ LOCK_TASK_FEATURE_KEYGUARD
+ })
public @interface LockTaskFeature {}
/**
@@ -3153,7 +3180,9 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag=true, value={FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY})
+ @IntDef(flag = true, prefix = { "FLAG_EVICT_" }, value = {
+ FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY
+ })
public @interface LockNowFlag {}
/**
@@ -3468,6 +3497,16 @@
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_START_ENCRYPTION
= "android.app.action.START_ENCRYPTION";
+
+ /**
+ * Broadcast action: notify managed provisioning that new managed user is created.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_MANAGED_USER_CREATED =
+ "android.app.action.MANAGED_USER_CREATED";
+
/**
* Widgets are enabled in keyguard
*/
@@ -3943,6 +3982,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.
*/
@@ -4212,16 +4295,16 @@
/**
* Called by a device owner to request a bugreport.
* <p>
- * If the device contains secondary users or profiles, they must be affiliated with the device
- * owner user. Otherwise a {@link SecurityException} will be thrown. See
- * {@link #setAffiliationIds}.
+ * If the device contains secondary users or profiles, they must be affiliated with the device.
+ * Otherwise a {@link SecurityException} will be thrown. See {@link #isAffiliatedUser}.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @return {@code true} if the bugreport collection started successfully, or {@code false} if it
* wasn't triggered because a previous bugreport operation is still active (either the
* bugreport is still running or waiting for the user to share or decline)
* @throws SecurityException if {@code admin} is not a device owner, or there is at least one
- * profile or secondary user that is not affiliated with the device owner user.
+ * profile or secondary user that is not affiliated with the device.
+ * @see #isAffiliatedUser
*/
public boolean requestBugreport(@NonNull ComponentName admin) {
throwIfParentInstance("requestBugreport");
@@ -6035,7 +6118,6 @@
* @return List of package names to keep cached.
* @see #setDelegatedScopes
* @see #DELEGATION_KEEP_UNINSTALLED_PACKAGES
- * @hide
*/
public @Nullable List<String> getKeepUninstalledPackages(@Nullable ComponentName admin) {
throwIfParentInstance("getKeepUninstalledPackages");
@@ -6063,7 +6145,6 @@
* @throws SecurityException if {@code admin} is not a device owner.
* @see #setDelegatedScopes
* @see #DELEGATION_KEEP_UNINSTALLED_PACKAGES
- * @hide
*/
public void setKeepUninstalledPackages(@Nullable ComponentName admin,
@NonNull List<String> packageNames) {
@@ -6151,21 +6232,27 @@
public static final int MAKE_USER_DEMO = 0x0004;
/**
- * Flag used by {@link #createAndManageUser} to specificy that the newly created user should be
+ * Flag used by {@link #createAndManageUser} to specify that the newly created user should be
* started in the background as part of the user creation.
*/
- // TODO: Investigate solutions for the case where reboot happens before setup is completed.
public static final int START_USER_IN_BACKGROUND = 0x0008;
/**
+ * Flag used by {@link #createAndManageUser} to specify that the newly created user should skip
+ * the disabling of system apps during provisioning.
+ */
+ public static final int LEAVE_ALL_SYSTEM_APPS_ENABLED = 0x0010;
+
+ /**
* @hide
*/
- @IntDef(
- flag = true,
- prefix = {"SKIP_", "MAKE_USER_", "START_"},
- value = {SKIP_SETUP_WIZARD, MAKE_USER_EPHEMERAL, MAKE_USER_DEMO,
- START_USER_IN_BACKGROUND}
- )
+ @IntDef(flag = true, prefix = { "SKIP_", "MAKE_USER_", "START_", "LEAVE_" }, value = {
+ SKIP_SETUP_WIZARD,
+ MAKE_USER_EPHEMERAL,
+ MAKE_USER_DEMO,
+ START_USER_IN_BACKGROUND,
+ LEAVE_ALL_SYSTEM_APPS_ENABLED
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface CreateAndManageUserFlags {}
@@ -6219,7 +6306,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 +6317,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 +6335,80 @@
}
/**
+ * 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 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.
+ * @see #isAffiliatedUser
+ */
+ 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();
+ }
+ }
+
+ /**
+ * Checks if the profile owner is running in an ephemeral user.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return whether the profile owner is running in an ephemeral user.
+ */
+ public boolean isEphemeralUser(@NonNull ComponentName admin) {
+ throwIfParentInstance("isEphemeralUser");
+ try {
+ return mService.isEphemeralUser(admin);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Retrieves the application restrictions for a given target application running in the calling
* user.
* <p>
@@ -6481,6 +6643,37 @@
}
/**
+ * Install an existing package that has been installed in another user, or has been kept after
+ * removal via {@link #setKeepUninstalledPackages}.
+ * This function can be called by a device owner, profile owner or a delegate given
+ * the {@link #DELEGATION_INSTALL_EXISTING_PACKAGE} scope via {@link #setDelegatedScopes}.
+ * When called in a secondary user or managed profile, the user/profile must be affiliated with
+ * the device. See {@link #isAffiliatedUser}.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param packageName The package to be installed in the calling profile.
+ * @return {@code true} if the app is installed; {@code false} otherwise.
+ * @throws SecurityException if {@code admin} is not the device owner, or the profile owner of
+ * an affiliated user or profile.
+ * @see #setKeepUninstalledPackages
+ * @see #setDelegatedScopes
+ * @see #isAffiliatedUser
+ * @see #DELEGATION_PACKAGE_ACCESS
+ */
+ public boolean installExistingPackage(@NonNull ComponentName admin, String packageName) {
+ throwIfParentInstance("installExistingPackage");
+ if (mService != null) {
+ try {
+ return mService.installExistingPackage(admin, mContext.getPackageName(),
+ packageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
* Called by a device owner or profile owner to disable account management for a specific type
* of account.
* <p>
@@ -6551,13 +6744,14 @@
* package list results in locked tasks belonging to those packages to be finished.
* <p>
* This function can only be called by the device owner or by a profile owner of a user/profile
- * that is affiliated with the device owner user. See {@link #setAffiliationIds}. Any packages
+ * that is affiliated with the device. See {@link #isAffiliatedUser}. Any packages
* set via this method will be cleared if the user becomes unaffiliated.
*
* @param packages The list of packages allowed to enter lock task mode
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @throws SecurityException if {@code admin} is not the device owner, or the profile owner of
* an affiliated user or profile.
+ * @see #isAffiliatedUser
* @see Activity#startLockTask()
* @see DeviceAdminReceiver#onLockTaskModeEntering(Context, Intent, String)
* @see DeviceAdminReceiver#onLockTaskModeExiting(Context, Intent)
@@ -6580,6 +6774,7 @@
*
* @throws SecurityException if {@code admin} is not the device owner, or the profile owner of
* an affiliated user or profile.
+ * @see #isAffiliatedUser
* @see #setLockTaskPackages
*/
public @NonNull String[] getLockTaskPackages(@NonNull ComponentName admin) {
@@ -6619,7 +6814,7 @@
* enabled.
* <p>
* This function can only be called by the device owner or by a profile owner of a user/profile
- * that is affiliated with the device owner user. See {@link #setAffiliationIds}. Any features
+ * that is affiliated with the device. See {@link #isAffiliatedUser}. Any features
* set via this method will be cleared if the user becomes unaffiliated.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -6633,6 +6828,7 @@
* {@link #LOCK_TASK_FEATURE_KEYGUARD}
* @throws SecurityException if {@code admin} is not the device owner, or the profile owner of
* an affiliated user or profile.
+ * @see #isAffiliatedUser
*/
public void setLockTaskFeatures(@NonNull ComponentName admin, @LockTaskFeature int flags) {
throwIfParentInstance("setLockTaskFeatures");
@@ -6652,7 +6848,8 @@
* @return bitfield of flags. See {@link #setLockTaskFeatures(ComponentName, int)} for a list.
* @throws SecurityException if {@code admin} is not the device owner, or the profile owner of
* an affiliated user or profile.
- * @see #setLockTaskFeatures(ComponentName, int)
+ * @see #isAffiliatedUser
+ * @see #setLockTaskFeatures
*/
public @LockTaskFeature int getLockTaskFeatures(@NonNull ComponentName admin) {
throwIfParentInstance("getLockTaskFeatures");
@@ -6667,7 +6864,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 +6913,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.
@@ -7619,6 +7847,7 @@
* @param admin Which device owner this request is associated with.
* @param enabled whether security logging should be enabled or not.
* @throws SecurityException if {@code admin} is not a device owner.
+ * @see #setAffiliationIds
* @see #retrieveSecurityLogs
*/
public void setSecurityLoggingEnabled(@NonNull ComponentName admin, boolean enabled) {
@@ -7657,14 +7886,14 @@
* owner has been notified via {@link DeviceAdminReceiver#onSecurityLogsAvailable}.
*
* <p>If there is any other user or profile on the device, it must be affiliated with the
- * device owner. Otherwise a {@link SecurityException} will be thrown. See
- * {@link #setAffiliationIds}
+ * device. Otherwise a {@link SecurityException} will be thrown. See {@link #isAffiliatedUser}.
*
* @param admin Which device owner this request is associated with.
* @return the new batch of security logs which is a list of {@link SecurityEvent},
* or {@code null} if rate limitation is exceeded or if logging is currently disabled.
* @throws SecurityException if {@code admin} is not a device owner, or there is at least one
- * profile or secondary user that is not affiliated with the device owner user.
+ * profile or secondary user that is not affiliated with the device.
+ * @see #isAffiliatedUser
* @see DeviceAdminReceiver#onSecurityLogsAvailable
*/
public @Nullable List<SecurityEvent> retrieveSecurityLogs(@NonNull ComponentName admin) {
@@ -7707,14 +7936,14 @@
* about data corruption when parsing. </strong>
*
* <p>If there is any other user or profile on the device, it must be affiliated with the
- * device owner. Otherwise a {@link SecurityException} will be thrown. See
- * {@link #setAffiliationIds}
+ * device. Otherwise a {@link SecurityException} will be thrown. See {@link #isAffiliatedUser}.
*
* @param admin Which device owner this request is associated with.
* @return Device logs from before the latest reboot of the system, or {@code null} if this API
* is not supported on the device.
* @throws SecurityException if {@code admin} is not a device owner, or there is at least one
- * profile or secondary user that is not affiliated with the device owner user.
+ * profile or secondary user that is not affiliated with the device.
+ * @see #isAffiliatedUser
* @see #retrieveSecurityLogs
*/
public @Nullable List<SecurityEvent> retrievePreRebootSecurityLogs(
@@ -7922,6 +8151,9 @@
* Indicates the entity that controls the device or profile owner. Two users/profiles are
* affiliated if the set of ids set by their device or profile owners intersect.
*
+ * <p>A user/profile that is affiliated with the device owner user is considered to be
+ * affiliated with the device.
+ *
* <p><strong>Note:</strong> Features that depend on user affiliation (such as security logging
* or {@link #bindDeviceAdminServiceAsUser}) won't be available when a secondary user or profile
* is created, until it becomes affiliated. Therefore it is recommended that the appropriate
@@ -7932,6 +8164,7 @@
* @param ids A set of opaque non-empty affiliation ids.
*
* @throws IllegalArgumentException if {@code ids} is null or contains an empty string.
+ * @see #isAffiliatedUser
*/
public void setAffiliationIds(@NonNull ComponentName admin, @NonNull Set<String> ids) {
throwIfParentInstance("setAffiliationIds");
@@ -7959,13 +8192,12 @@
}
/**
- * @hide
* 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 #setAffiliationIds} intersects with the device owner's.
- *
+ * @see #setAffiliationIds
*/
public boolean isAffiliatedUser() {
throwIfParentInstance("isAffiliatedUser");
@@ -8178,6 +8410,7 @@
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param enabled whether network logging should be enabled or not.
* @throws SecurityException if {@code admin} is not a device owner.
+ * @see #setAffiliationIds
* @see #retrieveNetworkLogs
*/
public void setNetworkLoggingEnabled(@NonNull ComponentName admin, boolean enabled) {
@@ -8233,7 +8466,8 @@
* {@code null} if the batch represented by batchToken is no longer available or if
* logging is disabled.
* @throws SecurityException if {@code admin} is not a device owner, or there is at least one
- * profile or secondary user that is not affiliated with the device owner user.
+ * profile or secondary user that is not affiliated with the device.
+ * @see #setAffiliationIds
* @see DeviceAdminReceiver#onNetworkLogsAvailable
*/
public @Nullable List<NetworkEvent> retrieveNetworkLogs(@NonNull ComponentName admin,
@@ -8411,6 +8645,15 @@
}
}
+ /** {@hide} */
+ @Condemned
+ @Deprecated
+ public boolean clearApplicationUserData(@NonNull ComponentName admin,
+ @NonNull String packageName, @NonNull OnClearApplicationUserDataListener listener,
+ @NonNull Handler handler) {
+ return clearApplicationUserData(admin, packageName, listener, new HandlerExecutor(handler));
+ }
+
/**
* Called by the device owner or profile owner to clear application user data of a given
* package. The behaviour of this is equivalent to the target application calling
@@ -8422,19 +8665,20 @@
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param packageName The name of the package which will have its user data wiped.
* @param listener A callback object that will inform the caller when the clearing is done.
- * @param handler The handler indicating the thread on which the listener should be invoked.
+ * @param executor The executor through which the listener should be invoked.
* @throws SecurityException if the caller is not the device owner/profile owner.
* @return whether the clearing succeeded.
*/
public boolean clearApplicationUserData(@NonNull ComponentName admin,
@NonNull String packageName, @NonNull OnClearApplicationUserDataListener listener,
- @NonNull Handler handler) {
+ @NonNull @CallbackExecutor Executor executor) {
throwIfParentInstance("clearAppData");
+ Preconditions.checkNotNull(executor);
try {
return mService.clearApplicationUserData(admin, packageName,
new IPackageDataObserver.Stub() {
public void onRemoveCompleted(String pkg, boolean succeeded) {
- handler.post(() ->
+ executor.execute(() ->
listener.onApplicationUserDataCleared(pkg, succeeded));
}
});
@@ -8444,6 +8688,37 @@
}
/**
+ * Called by a device owner to specify whether logout 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 should be enabled or not.
+ * @throws SecurityException if {@code admin} is not a device owner.
+ */
+ public void setLogoutEnabled(@NonNull ComponentName admin, boolean enabled) {
+ throwIfParentInstance("setLogoutEnabled");
+ try {
+ mService.setLogoutEnabled(admin, enabled);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether logout is enabled by a device owner.
+ *
+ * @return {@code true} if logout is enabled by device owner, {@code false} otherwise.
+ */
+ public boolean isLogoutEnabled() {
+ throwIfParentInstance("isLogoutEnabled");
+ try {
+ return mService.isLogoutEnabled();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Callback used in {@link #clearApplicationUserData}
* to indicate that the clearing of an application's user data is done.
*/
@@ -8457,4 +8732,25 @@
*/
void onApplicationUserDataCleared(String packageName, boolean succeeded);
}
+
+ /**
+ * Returns set of system apps that should be removed during provisioning.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param userId ID of the user to be provisioned.
+ * @param provisioningAction action indicating type of provisioning, should be one of
+ * {@link #ACTION_PROVISION_MANAGED_DEVICE}, {@link #ACTION_PROVISION_MANAGED_PROFILE} or
+ * {@link #ACTION_PROVISION_MANAGED_USER}.
+ *
+ * @hide
+ */
+ public Set<String> getDisallowedSystemApps(ComponentName admin, int userId,
+ String provisioningAction) {
+ try {
+ return new ArraySet<>(
+ mService.getDisallowedSystemApps(admin, userId, provisioningAction));
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
}
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/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b7740e9..b76618b 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,9 +217,13 @@
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);
+ boolean installExistingPackage(in ComponentName admin, in String callerPackage, in String packageName);
void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled);
String[] getAccountTypesWithManagementDisabled();
@@ -231,6 +237,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);
@@ -351,6 +358,7 @@
IApplicationThread caller, IBinder token, in Intent service,
IServiceConnection connection, int flags, int targetUserId);
List<UserHandle> getBindDeviceAdminTargetUsers(in ComponentName admin);
+ boolean isEphemeralUser(in ComponentName admin);
long getLastSecurityLogRetrievalTime();
long getLastBugReportRequestTime();
@@ -365,4 +373,9 @@
StringParceledListSlice getOwnerInstalledCaCerts(in UserHandle user);
boolean clearApplicationUserData(in ComponentName admin, in String packageName, in IPackageDataObserver callback);
+
+ void setLogoutEnabled(in ComponentName admin, boolean enabled);
+ boolean isLogoutEnabled();
+
+ List<String> getDisallowedSystemApps(in ComponentName admin, int userId, String provisioningAction);
}
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java
index 4658a47..5fee853 100644
--- a/core/java/android/app/admin/PasswordMetrics.java
+++ b/core/java/android/app/admin/PasswordMetrics.java
@@ -223,7 +223,12 @@
}
@Retention(RetentionPolicy.SOURCE)
- @IntDef({CHAR_UPPER_CASE, CHAR_LOWER_CASE, CHAR_DIGIT, CHAR_SYMBOL})
+ @IntDef(prefix = { "CHAR_" }, value = {
+ CHAR_UPPER_CASE,
+ CHAR_LOWER_CASE,
+ CHAR_DIGIT,
+ CHAR_SYMBOL
+ })
private @interface CharacterCatagory {}
private static final int CHAR_LOWER_CASE = 0;
private static final int CHAR_UPPER_CASE = 1;
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 2b590e0..0f93c59 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -43,10 +43,17 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({TAG_ADB_SHELL_INTERACTIVE, TAG_ADB_SHELL_CMD, TAG_SYNC_RECV_FILE, TAG_SYNC_SEND_FILE,
- TAG_APP_PROCESS_START, TAG_KEYGUARD_DISMISSED, TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT,
- TAG_KEYGUARD_SECURED})
- public @interface SECURITY_LOG_TAG {}
+ @IntDef(prefix = { "TAG_" }, value = {
+ TAG_ADB_SHELL_INTERACTIVE,
+ TAG_ADB_SHELL_CMD,
+ TAG_SYNC_RECV_FILE,
+ TAG_SYNC_SEND_FILE,
+ TAG_APP_PROCESS_START,
+ TAG_KEYGUARD_DISMISSED,
+ TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT,
+ TAG_KEYGUARD_SECURED
+ })
+ public @interface SecurityLogTag {}
/**
* Indicate that an ADB interactive shell was opened via "adb shell".
@@ -143,13 +150,8 @@
/**
* Returns the tag of this log entry, which specifies entry's semantics.
- * Could be one of {@link SecurityLog#TAG_SYNC_RECV_FILE},
- * {@link SecurityLog#TAG_SYNC_SEND_FILE}, {@link SecurityLog#TAG_ADB_SHELL_CMD},
- * {@link SecurityLog#TAG_ADB_SHELL_INTERACTIVE}, {@link SecurityLog#TAG_APP_PROCESS_START},
- * {@link SecurityLog#TAG_KEYGUARD_DISMISSED}, {@link SecurityLog#TAG_KEYGUARD_SECURED},
- * {@link SecurityLog#TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT}.
*/
- public @SECURITY_LOG_TAG int getTag() {
+ public @SecurityLogTag int getTag() {
return mEvent.getTag();
}
diff --git a/core/java/android/app/admin/SystemUpdateInfo.java b/core/java/android/app/admin/SystemUpdateInfo.java
index fa31273..b0376b5 100644
--- a/core/java/android/app/admin/SystemUpdateInfo.java
+++ b/core/java/android/app/admin/SystemUpdateInfo.java
@@ -52,7 +52,11 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({SECURITY_PATCH_STATE_FALSE, SECURITY_PATCH_STATE_TRUE, SECURITY_PATCH_STATE_UNKNOWN})
+ @IntDef(prefix = { "SECURITY_PATCH_STATE_" }, value = {
+ SECURITY_PATCH_STATE_FALSE,
+ SECURITY_PATCH_STATE_TRUE,
+ SECURITY_PATCH_STATE_UNKNOWN
+ })
public @interface SecurityPatchState {}
private static final String ATTR_RECEIVED_TIME = "received-time";
diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java
index 995d98a..232a688 100644
--- a/core/java/android/app/admin/SystemUpdatePolicy.java
+++ b/core/java/android/app/admin/SystemUpdatePolicy.java
@@ -36,10 +36,11 @@
public class SystemUpdatePolicy implements Parcelable {
/** @hide */
- @IntDef({
- TYPE_INSTALL_AUTOMATIC,
- TYPE_INSTALL_WINDOWED,
- TYPE_POSTPONE})
+ @IntDef(prefix = { "TYPE_" }, value = {
+ TYPE_INSTALL_AUTOMATIC,
+ TYPE_INSTALL_WINDOWED,
+ TYPE_POSTPONE
+ })
@Retention(RetentionPolicy.SOURCE)
@interface SystemUpdatePolicyType {}
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
index 07001e2..a2b7d58 100644
--- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
@@ -19,25 +19,25 @@
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 final Configuration mConfiguration;
-
- public ActivityConfigurationChangeItem(Configuration configuration) {
- mConfiguration = configuration;
- }
+ private Configuration mConfiguration;
@Override
- public void execute(android.app.ClientTransactionHandler client, IBinder token) {
+ 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);
@@ -45,6 +45,29 @@
}
+ // 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. */
@@ -78,11 +101,16 @@
return false;
}
final ActivityConfigurationChangeItem other = (ActivityConfigurationChangeItem) o;
- return mConfiguration.equals(other.mConfiguration);
+ 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
index a64108d..0fdc7c5 100644
--- a/core/java/android/app/servertransaction/ActivityLifecycleItem.java
+++ b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
@@ -27,16 +27,28 @@
*/
public abstract class ActivityLifecycleItem extends ClientTransactionItem {
- static final boolean DEBUG_ORDER = false;
-
- @IntDef({UNDEFINED, RESUMED, PAUSED, STOPPED, DESTROYED})
+ @IntDef(prefix = { "UNDEFINED", "PRE_", "ON_" }, value = {
+ UNDEFINED,
+ PRE_ON_CREATE,
+ ON_CREATE,
+ ON_START,
+ ON_RESUME,
+ ON_PAUSE,
+ ON_STOP,
+ ON_DESTROY,
+ ON_RESTART
+ })
@Retention(RetentionPolicy.SOURCE)
- @interface LifecycleState{}
+ public @interface LifecycleState{}
public static final int UNDEFINED = -1;
- public static final int RESUMED = 0;
- public static final int PAUSED = 1;
- public static final int STOPPED = 2;
- public static final int DESTROYED = 3;
+ 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
diff --git a/core/java/android/app/servertransaction/ActivityResultItem.java b/core/java/android/app/servertransaction/ActivityResultItem.java
index 76664d8..73b5ec4 100644
--- a/core/java/android/app/servertransaction/ActivityResultItem.java
+++ b/core/java/android/app/servertransaction/ActivityResultItem.java
@@ -16,9 +16,10 @@
package android.app.servertransaction;
-import static android.app.servertransaction.ActivityLifecycleItem.PAUSED;
+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;
@@ -26,6 +27,7 @@
import android.os.Trace;
import java.util.List;
+import java.util.Objects;
/**
* Activity result delivery callback.
@@ -33,25 +35,44 @@
*/
public class ActivityResultItem extends ClientTransactionItem {
- private final List<ResultInfo> mResultInfoList;
-
- public ActivityResultItem(List<ResultInfo> resultInfos) {
- mResultInfoList = resultInfos;
- }
+ private List<ResultInfo> mResultInfoList;
@Override
public int getPreExecutionState() {
- return PAUSED;
+ return ON_PAUSE;
}
@Override
- public void execute(android.app.ClientTransactionHandler client, IBinder token) {
+ 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. */
@@ -85,11 +106,16 @@
return false;
}
final ActivityResultItem other = (ActivityResultItem) o;
- return mResultInfoList.equals(other.mResultInfoList);
+ 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
index 4bd01af..c91e0ca 100644
--- a/core/java/android/app/servertransaction/BaseClientRequest.java
+++ b/core/java/android/app/servertransaction/BaseClientRequest.java
@@ -24,7 +24,7 @@
* Each of them can be prepared before scheduling and, eventually, executed.
* @hide
*/
-public interface BaseClientRequest {
+public interface BaseClientRequest extends ObjectPoolItem {
/**
* Prepare the client request before scheduling.
@@ -33,13 +33,25 @@
* @param client Target client handler.
* @param token Target activity token.
*/
- default void prepare(ClientTransactionHandler client, IBinder 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);
+ 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/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java
index d2289ba..764ceed 100644
--- a/core/java/android/app/servertransaction/ClientTransaction.java
+++ b/core/java/android/app/servertransaction/ClientTransaction.java
@@ -16,6 +16,7 @@
package android.app.servertransaction;
+import android.annotation.Nullable;
import android.app.ClientTransactionHandler;
import android.app.IApplicationThread;
import android.os.IBinder;
@@ -36,7 +37,7 @@
* @see ActivityLifecycleItem
* @hide
*/
-public class ClientTransaction implements Parcelable {
+public class ClientTransaction implements Parcelable, ObjectPoolItem {
/** A list of individual callbacks to a client. */
private List<ClientTransactionItem> mActivityCallbacks;
@@ -53,11 +54,6 @@
/** Target client activity. Might be null if the entire transaction is targeting an app. */
private IBinder mActivityToken;
- public ClientTransaction(IApplicationThread client, IBinder activityToken) {
- mClient = client;
- mActivityToken = activityToken;
- }
-
/**
* Add a message to the end of the sequence of callbacks.
* @param activityCallback A single message that can contain a lifecycle request/callback.
@@ -69,6 +65,23 @@
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.
@@ -82,50 +95,68 @@
* @param clientTransactionHandler Handler on the client side that will executed all operations
* requested by transaction items.
*/
- public void prepare(android.app.ClientTransactionHandler clientTransactionHandler) {
+ 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).prepare(clientTransactionHandler, mActivityToken);
+ mActivityCallbacks.get(i).preExecute(clientTransactionHandler, mActivityToken);
}
}
if (mLifecycleStateRequest != null) {
- mLifecycleStateRequest.prepare(clientTransactionHandler, mActivityToken);
- }
- }
-
- /**
- * Execute the transaction.
- * @param clientTransactionHandler Handler on the client side that will execute all operations
- * requested by transaction items.
- */
- public void execute(android.app.ClientTransactionHandler clientTransactionHandler) {
- if (mActivityCallbacks != null) {
- final int size = mActivityCallbacks.size();
- for (int i = 0; i < size; ++i) {
- mActivityCallbacks.get(i).execute(clientTransactionHandler, mActivityToken);
- }
- }
- if (mLifecycleStateRequest != null) {
- mLifecycleStateRequest.execute(clientTransactionHandler, mActivityToken);
+ 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 #prepare(ClientTransactionHandler)}, which triggers all work that
- * needs to be done before actually scheduling the transaction for callbacks and lifecycle
- * state request.
+ * 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 #execute(ClientTransactionHandler)}, which executes all callbacks
- * and necessary lifecycle transitions.
+ * 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. */
diff --git a/core/java/android/app/servertransaction/ConfigurationChangeItem.java b/core/java/android/app/servertransaction/ConfigurationChangeItem.java
index 055923e..4ab7251 100644
--- a/core/java/android/app/servertransaction/ConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ConfigurationChangeItem.java
@@ -16,32 +16,55 @@
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 final Configuration mConfiguration;
-
- public ConfigurationChangeItem(Configuration configuration) {
- mConfiguration = new Configuration(configuration);
- }
+ private Configuration mConfiguration;
@Override
- public void prepare(android.app.ClientTransactionHandler client, IBinder token) {
+ public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
client.updatePendingConfiguration(mConfiguration);
}
@Override
- public void execute(android.app.ClientTransactionHandler client, IBinder token) {
+ 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. */
@@ -75,11 +98,16 @@
return false;
}
final ConfigurationChangeItem other = (ConfigurationChangeItem) o;
- return mConfiguration.equals(other.mConfiguration);
+ 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
index 38fd5fb..83da5f3 100644
--- a/core/java/android/app/servertransaction/DestroyActivityItem.java
+++ b/core/java/android/app/servertransaction/DestroyActivityItem.java
@@ -29,16 +29,12 @@
*/
public class DestroyActivityItem extends ActivityLifecycleItem {
- private final boolean mFinished;
- private final int mConfigChanges;
-
- public DestroyActivityItem(boolean finished, int configChanges) {
- mFinished = finished;
- mConfigChanges = configChanges;
- }
+ private boolean mFinished;
+ private int mConfigChanges;
@Override
- public void execute(ClientTransactionHandler client, IBinder token) {
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
client.handleDestroyActivity(token, mFinished, mConfigChanges,
false /* getNonConfigInstance */);
@@ -47,7 +43,31 @@
@Override
public int getTargetState() {
- return DESTROYED;
+ 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);
}
@@ -96,4 +116,10 @@
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
index 417ebac..7be82bf 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -18,6 +18,7 @@
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;
@@ -42,68 +43,69 @@
* Request to launch an activity.
* @hide
*/
-public class LaunchActivityItem extends ActivityLifecycleItem {
+public class LaunchActivityItem extends ClientTransactionItem {
- private final Intent mIntent;
- private final int mIdent;
- private final ActivityInfo mInfo;
- private final Configuration mCurConfig;
- private final Configuration mOverrideConfig;
- private final CompatibilityInfo mCompatInfo;
- private final String mReferrer;
- private final IVoiceInteractor mVoiceInteractor;
- private final int mProcState;
- private final Bundle mState;
- private final PersistableBundle mPersistentState;
- private final List<ResultInfo> mPendingResults;
- private final List<ReferrerIntent> mPendingNewIntents;
- // TODO(lifecycler): use lifecycle request instead of this param.
- private final boolean mNotResumed;
- private final boolean mIsForward;
- private final ProfilerInfo mProfilerInfo;
-
- public LaunchActivityItem(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 notResumed, boolean isForward,
- ProfilerInfo profilerInfo) {
- mIntent = intent;
- mIdent = ident;
- mInfo = info;
- mCurConfig = curConfig;
- mOverrideConfig = overrideConfig;
- mCompatInfo = compatInfo;
- mReferrer = referrer;
- mVoiceInteractor = voiceInteractor;
- mProcState = procState;
- mState = state;
- mPersistentState = persistentState;
- mPendingResults = pendingResults;
- mPendingNewIntents = pendingNewIntents;
- mNotResumed = notResumed;
- mIsForward = isForward;
- mProfilerInfo = profilerInfo;
- }
+ 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 prepare(ClientTransactionHandler client, IBinder token) {
+ public void preExecute(ClientTransactionHandler client, IBinder token) {
client.updateProcessState(mProcState, false);
client.updatePendingConfiguration(mCurConfig);
}
@Override
- public void execute(ClientTransactionHandler client, IBinder token) {
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
- client.handleLaunchActivity(token, mIntent, mIdent, mInfo, mOverrideConfig, mCompatInfo,
- mReferrer, mVoiceInteractor, mState, mPersistentState, mPendingResults,
- mPendingNewIntents, mNotResumed, mIsForward, mProfilerInfo);
+ 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 int getTargetState() {
- return mNotResumed ? PAUSED : RESUMED;
+ public void recycle() {
+ setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null,
+ false, null);
+ ObjectPool.recycle(this);
}
@@ -119,35 +121,28 @@
dest.writeTypedObject(mOverrideConfig, flags);
dest.writeTypedObject(mCompatInfo, flags);
dest.writeString(mReferrer);
- dest.writeStrongBinder(mVoiceInteractor != null ? mVoiceInteractor.asBinder() : null);
+ dest.writeStrongInterface(mVoiceInteractor);
dest.writeInt(mProcState);
dest.writeBundle(mState);
dest.writePersistableBundle(mPersistentState);
dest.writeTypedList(mPendingResults, flags);
dest.writeTypedList(mPendingNewIntents, flags);
- dest.writeBoolean(mNotResumed);
dest.writeBoolean(mIsForward);
dest.writeTypedObject(mProfilerInfo, flags);
}
/** Read from Parcel. */
private LaunchActivityItem(Parcel in) {
- mIntent = in.readTypedObject(Intent.CREATOR);
- mIdent = in.readInt();
- mInfo = in.readTypedObject(ActivityInfo.CREATOR);
- mCurConfig = in.readTypedObject(Configuration.CREATOR);
- mOverrideConfig = in.readTypedObject(Configuration.CREATOR);
- mCompatInfo = in.readTypedObject(CompatibilityInfo.CREATOR);
- mReferrer = in.readString();
- mVoiceInteractor = (IVoiceInteractor) in.readStrongBinder();
- mProcState = in.readInt();
- mState = in.readBundle(getClass().getClassLoader());
- mPersistentState = in.readPersistableBundle(getClass().getClassLoader());
- mPendingResults = in.createTypedArrayList(ResultInfo.CREATOR);
- mPendingNewIntents = in.createTypedArrayList(ReferrerIntent.CREATOR);
- mNotResumed = in.readBoolean();
- mIsForward = in.readBoolean();
- mProfilerInfo = in.readTypedObject(ProfilerInfo.CREATOR);
+ 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 =
@@ -170,7 +165,9 @@
return false;
}
final LaunchActivityItem other = (LaunchActivityItem) o;
- return mIntent.filterEquals(other.mIntent) && mIdent == other.mIdent
+ 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)
@@ -179,7 +176,7 @@
&& areBundlesEqual(mPersistentState, other.mPersistentState)
&& Objects.equals(mPendingResults, other.mPendingResults)
&& Objects.equals(mPendingNewIntents, other.mPendingNewIntents)
- && mNotResumed == other.mNotResumed && mIsForward == other.mIsForward
+ && mIsForward == other.mIsForward
&& Objects.equals(mProfilerInfo, other.mProfilerInfo);
}
@@ -197,14 +194,17 @@
result = 31 * result + (mPersistentState != null ? mPersistentState.size() : 0);
result = 31 * result + Objects.hashCode(mPendingResults);
result = 31 * result + Objects.hashCode(mPendingNewIntents);
- result = 31 * result + (mNotResumed ? 1 : 0);
result = 31 * result + (mIsForward ? 1 : 0);
result = 31 * result + Objects.hashCode(mProfilerInfo);
return result;
}
private boolean activityInfoEqual(ActivityInfo other) {
- return mInfo.flags == other.flags && mInfo.maxAspectRatio == other.maxAspectRatio
+ 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());
}
@@ -229,4 +229,38 @@
}
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
index ccd80d8..b3dddfb3 100644
--- a/core/java/android/app/servertransaction/MoveToDisplayItem.java
+++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java
@@ -18,33 +18,56 @@
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 final int mTargetDisplayId;
- private final Configuration mConfiguration;
-
- public MoveToDisplayItem(int targetDisplayId, Configuration configuration) {
- mTargetDisplayId = targetDisplayId;
- mConfiguration = configuration;
- }
+ private int mTargetDisplayId;
+ private Configuration mConfiguration;
@Override
- public void execute(android.app.ClientTransactionHandler client, IBinder token) {
+ 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. */
@@ -80,7 +103,7 @@
}
final MoveToDisplayItem other = (MoveToDisplayItem) o;
return mTargetDisplayId == other.mTargetDisplayId
- && mConfiguration.equals(other.mConfiguration);
+ && Objects.equals(mConfiguration, other.mConfiguration);
}
@Override
@@ -90,4 +113,10 @@
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
index a0c617f..c3022d6 100644
--- a/core/java/android/app/servertransaction/MultiWindowModeChangeItem.java
+++ b/core/java/android/app/servertransaction/MultiWindowModeChangeItem.java
@@ -16,10 +16,13 @@
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
@@ -28,18 +31,38 @@
// communicate multi-window mode change with WindowConfiguration.
public class MultiWindowModeChangeItem extends ClientTransactionItem {
- private final boolean mIsInMultiWindowMode;
- private final Configuration mOverrideConfig;
+ private boolean mIsInMultiWindowMode;
+ private Configuration mOverrideConfig;
- public MultiWindowModeChangeItem(boolean isInMultiWindowMode,
+ @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) {
- mIsInMultiWindowMode = isInMultiWindowMode;
- mOverrideConfig = overrideConfig;
+ MultiWindowModeChangeItem instance = ObjectPool.obtain(MultiWindowModeChangeItem.class);
+ if (instance == null) {
+ instance = new MultiWindowModeChangeItem();
+ }
+ instance.mIsInMultiWindowMode = isInMultiWindowMode;
+ instance.mOverrideConfig = overrideConfig;
+
+ return instance;
}
@Override
- public void execute(android.app.ClientTransactionHandler client, IBinder token) {
- client.handleMultiWindowModeChanged(token, mIsInMultiWindowMode, mOverrideConfig);
+ public void recycle() {
+ mIsInMultiWindowMode = false;
+ mOverrideConfig = null;
+ ObjectPool.recycle(this);
}
@@ -79,7 +102,7 @@
}
final MultiWindowModeChangeItem other = (MultiWindowModeChangeItem) o;
return mIsInMultiWindowMode == other.mIsInMultiWindowMode
- && mOverrideConfig.equals(other.mOverrideConfig);
+ && Objects.equals(mOverrideConfig, other.mOverrideConfig);
}
@Override
@@ -89,4 +112,10 @@
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
index 61a8965..7dfde73 100644
--- a/core/java/android/app/servertransaction/NewIntentItem.java
+++ b/core/java/android/app/servertransaction/NewIntentItem.java
@@ -16,9 +16,7 @@
package android.app.servertransaction;
-import static android.app.servertransaction.ActivityLifecycleItem.PAUSED;
-import static android.app.servertransaction.ActivityLifecycleItem.RESUMED;
-
+import android.app.ClientTransactionHandler;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -27,6 +25,7 @@
import com.android.internal.content.ReferrerIntent;
import java.util.List;
+import java.util.Objects;
/**
* New intent message.
@@ -34,32 +33,53 @@
*/
public class NewIntentItem extends ClientTransactionItem {
- private final List<ReferrerIntent> mIntents;
- private final boolean mPause;
+ private List<ReferrerIntent> mIntents;
+ private boolean mPause;
- public NewIntentItem(List<ReferrerIntent> intents, boolean pause) {
- mIntents = intents;
- mPause = pause;
- }
-
- @Override
+ // TODO(lifecycler): Switch new intent handling to this scheme.
+ /*@Override
public int getPreExecutionState() {
- return PAUSED;
+ return ON_PAUSE;
}
@Override
public int getPostExecutionState() {
- return RESUMED;
- }
+ return ON_RESUME;
+ }*/
@Override
- public void execute(android.app.ClientTransactionHandler client, IBinder token) {
+ 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. */
@@ -95,7 +115,7 @@
return false;
}
final NewIntentItem other = (NewIntentItem) o;
- return mPause == other.mPause && mIntents.equals(other.mIntents);
+ return mPause == other.mPause && Objects.equals(mIntents, other.mIntents);
}
@Override
@@ -105,4 +125,9 @@
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
index e561a4b..880fef7 100644
--- a/core/java/android/app/servertransaction/PauseActivityItem.java
+++ b/core/java/android/app/servertransaction/PauseActivityItem.java
@@ -18,11 +18,12 @@
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;
-import android.util.Slog;
/**
* Request to move an activity to paused state.
@@ -32,43 +33,81 @@
private static final String TAG = "PauseActivityItem";
- private final boolean mFinished;
- private final boolean mUserLeaving;
- private final int mConfigChanges;
- private final boolean mDontReport;
-
- private int mLifecycleSeq;
-
- public PauseActivityItem(boolean finished, boolean userLeaving, int configChanges,
- boolean dontReport) {
- mFinished = finished;
- mUserLeaving = userLeaving;
- mConfigChanges = configChanges;
- mDontReport = dontReport;
- }
+ private boolean mFinished;
+ private boolean mUserLeaving;
+ private int mConfigChanges;
+ private boolean mDontReport;
@Override
- public void prepare(ClientTransactionHandler client, IBinder token) {
- mLifecycleSeq = client.getLifecycleSeq();
- if (DEBUG_ORDER) {
- Slog.d(TAG, "Pause transaction for " + client + " received seq: "
- + mLifecycleSeq);
- }
- }
-
- @Override
- public void execute(ClientTransactionHandler client, IBinder token) {
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, mDontReport,
- mLifecycleSeq);
+ pendingActions);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@Override
public int getTargetState() {
- return PAUSED;
+ 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
@@ -122,4 +161,10 @@
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
index 923839e..b999cd7 100644
--- a/core/java/android/app/servertransaction/PipModeChangeItem.java
+++ b/core/java/android/app/servertransaction/PipModeChangeItem.java
@@ -16,10 +16,13 @@
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
@@ -28,17 +31,37 @@
// communicate multi-window mode change with WindowConfiguration.
public class PipModeChangeItem extends ClientTransactionItem {
- private final boolean mIsInPipMode;
- private final Configuration mOverrideConfig;
+ private boolean mIsInPipMode;
+ private Configuration mOverrideConfig;
- public PipModeChangeItem(boolean isInPipMode, Configuration overrideConfig) {
- mIsInPipMode = isInPipMode;
- mOverrideConfig = overrideConfig;
+ @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 execute(android.app.ClientTransactionHandler client, IBinder token) {
- client.handlePictureInPictureModeChanged(token, mIsInPipMode, mOverrideConfig);
+ public void recycle() {
+ mIsInPipMode = false;
+ mOverrideConfig = null;
+ ObjectPool.recycle(this);
}
@@ -76,7 +99,8 @@
return false;
}
final PipModeChangeItem other = (PipModeChangeItem) o;
- return mIsInPipMode == other.mIsInPipMode && mOverrideConfig.equals(other.mOverrideConfig);
+ return mIsInPipMode == other.mIsInPipMode
+ && Objects.equals(mOverrideConfig, other.mOverrideConfig);
}
@Override
@@ -86,4 +110,10 @@
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
index ea31a46..9249c6e 100644
--- a/core/java/android/app/servertransaction/ResumeActivityItem.java
+++ b/core/java/android/app/servertransaction/ResumeActivityItem.java
@@ -18,11 +18,12 @@
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;
-import android.util.Slog;
/**
* Request to move an activity to resumed state.
@@ -32,37 +33,78 @@
private static final String TAG = "ResumeActivityItem";
- private final int mProcState;
- private final boolean mIsForward;
-
- private int mLifecycleSeq;
-
- public ResumeActivityItem(int procState, boolean isForward) {
- mProcState = procState;
- mIsForward = isForward;
- }
+ private int mProcState;
+ private boolean mUpdateProcState;
+ private boolean mIsForward;
@Override
- public void prepare(ClientTransactionHandler client, IBinder token) {
- mLifecycleSeq = client.getLifecycleSeq();
- if (DEBUG_ORDER) {
- Slog.d(TAG, "Resume transaction for " + client + " received seq: "
- + mLifecycleSeq);
+ public void preExecute(ClientTransactionHandler client, IBinder token) {
+ if (mUpdateProcState) {
+ client.updateProcessState(mProcState, false);
}
- client.updateProcessState(mProcState, false);
}
@Override
- public void execute(ClientTransactionHandler client, IBinder token) {
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
- client.handleResumeActivity(token, true /* clearHide */, mIsForward,
- true /* reallyResume */, mLifecycleSeq, "RESUME_ACTIVITY");
+ 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 RESUMED;
+ 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);
}
@@ -72,12 +114,14 @@
@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();
}
@@ -101,14 +145,22 @@
return false;
}
final ResumeActivityItem other = (ResumeActivityItem) o;
- return mProcState == other.mProcState && mIsForward == other.mIsForward;
+ 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
index d62c507..5c5c304 100644
--- a/core/java/android/app/servertransaction/StopActivityItem.java
+++ b/core/java/android/app/servertransaction/StopActivityItem.java
@@ -22,7 +22,6 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.Trace;
-import android.util.Slog;
/**
* Request to move an activity to stopped state.
@@ -32,35 +31,50 @@
private static final String TAG = "StopActivityItem";
- private final boolean mShowWindow;
- private final int mConfigChanges;
-
- private int mLifecycleSeq;
-
- public StopActivityItem(boolean showWindow, int configChanges) {
- mShowWindow = showWindow;
- mConfigChanges = configChanges;
- }
+ private boolean mShowWindow;
+ private int mConfigChanges;
@Override
- public void prepare(ClientTransactionHandler client, IBinder token) {
- mLifecycleSeq = client.getLifecycleSeq();
- if (DEBUG_ORDER) {
- Slog.d(TAG, "Stop transaction for " + client + " received seq: "
- + mLifecycleSeq);
- }
- }
-
- @Override
- public void execute(ClientTransactionHandler client, IBinder token) {
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
- client.handleStopActivity(token, mShowWindow, mConfigChanges, mLifecycleSeq);
+ 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 STOPPED;
+ 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);
}
@@ -109,4 +123,10 @@
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
index 8e88b38..d9956b1 100644
--- a/core/java/android/app/servertransaction/WindowVisibilityItem.java
+++ b/core/java/android/app/servertransaction/WindowVisibilityItem.java
@@ -18,6 +18,7 @@
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;
@@ -28,20 +29,39 @@
*/
public class WindowVisibilityItem extends ClientTransactionItem {
- private final boolean mShowWindow;
-
- public WindowVisibilityItem(boolean showWindow) {
- mShowWindow = showWindow;
- }
+ private boolean mShowWindow;
@Override
- public void execute(android.app.ClientTransactionHandler client, IBinder token) {
+ 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. */
@@ -82,4 +102,9 @@
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/ISliceListener.aidl
similarity index 63%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to core/java/android/app/slice/ISliceListener.aidl
index 4ccdea5..d293fd4 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/core/java/android/app/slice/ISliceListener.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,12 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package android.app.slice;
-import android.telephony.SubscriptionInfo;
+import android.app.slice.ISliceManager;
+import android.app.slice.Slice;
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
+/** @hide */
+oneway interface ISliceListener {
+ void onSliceUpdated(in Slice s);
}
-
diff --git a/core/java/android/app/slice/ISliceManager.aidl b/core/java/android/app/slice/ISliceManager.aidl
new file mode 100644
index 0000000..5f0e542
--- /dev/null
+++ b/core/java/android/app/slice/ISliceManager.aidl
@@ -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.
+ */
+
+package android.app.slice;
+
+import android.app.slice.ISliceListener;
+import android.app.slice.SliceSpec;
+import android.net.Uri;
+
+/** @hide */
+interface ISliceManager {
+ void addSliceListener(in Uri uri, String pkg, in ISliceListener listener,
+ in SliceSpec[] specs);
+ void removeSliceListener(in Uri uri, String pkg, in ISliceListener listener);
+ void pinSlice(String pkg, in Uri uri, in SliceSpec[] specs);
+ void unpinSlice(String pkg, in Uri uri);
+ boolean hasSliceAccess(String pkg);
+ SliceSpec[] getPinnedSpecs(in Uri uri, String pkg);
+}
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/core/java/android/app/slice/Slice.aidl
similarity index 64%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to core/java/android/app/slice/Slice.aidl
index 4ccdea5..e097f9d 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/core/java/android/app/slice/Slice.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.app.slice;
-import android.telephony.SubscriptionInfo;
-
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
-}
-
+parcelable Slice;
diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java
index ddc5760..b13067e 100644
--- a/core/java/android/app/slice/Slice.java
+++ b/core/java/android/app/slice/Slice.java
@@ -37,6 +37,8 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -53,9 +55,21 @@
/**
* @hide
*/
- @StringDef({HINT_TITLE, HINT_LIST, HINT_LIST_ITEM, HINT_LARGE, HINT_ACTIONS, HINT_SELECTED,
- HINT_NO_TINT, HINT_PARTIAL})
- public @interface SliceHint{ }
+ @StringDef(prefix = { "HINT_" }, value = {
+ HINT_TITLE,
+ HINT_LIST,
+ HINT_LIST_ITEM,
+ HINT_LARGE,
+ HINT_ACTIONS,
+ HINT_SELECTED,
+ HINT_NO_TINT,
+ HINT_HIDDEN,
+ HINT_TOGGLE,
+ HINT_HORIZONTAL,
+ HINT_PARTIAL,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SliceHint {}
/**
* The meta-data key that allows an activity to easily be linked directly to a slice.
@@ -129,6 +143,11 @@
* OS and should not be cached by apps.
*/
public static final String HINT_PARTIAL = "partial";
+ /**
+ * A hint representing that this item is the max value possible for the slice containing this.
+ * Used to indicate the maximum integer value for a {@link #SUBTYPE_SLIDER}.
+ */
+ public static final String HINT_MAX = "max";
/**
* Key to retrieve an extra added to an intent when a control is changed.
@@ -144,6 +163,14 @@
* Subtype to tag the source (i.e. sender) of a {@link #SUBTYPE_MESSAGE}.
*/
public static final String SUBTYPE_SOURCE = "source";
+ /**
+ * Subtype to tag an item as representing a color.
+ */
+ public static final String SUBTYPE_COLOR = "color";
+ /**
+ * Subtype to tag an item represents a slider.
+ */
+ public static final String SUBTYPE_SLIDER = "slider";
private final SliceItem[] mItems;
private final @SliceHint String[] mHints;
@@ -375,9 +402,31 @@
* Add a color to the slice being constructed
* @param subType Optional template-specific type information
* @see {@link SliceItem#getSubType()}
+ * @deprecated will be removed once supportlib updates
*/
public Builder addColor(int color, @Nullable String subType, @SliceHint String... hints) {
- mItems.add(new SliceItem(color, SliceItem.FORMAT_COLOR, subType, hints));
+ mItems.add(new SliceItem(color, SliceItem.FORMAT_INT, subType, hints));
+ return this;
+ }
+
+ /**
+ * Add a color to the slice being constructed
+ * @param subType Optional template-specific type information
+ * @see {@link SliceItem#getSubType()}
+ * @deprecated will be removed once supportlib updates
+ */
+ public Builder addColor(int color, @Nullable String subType,
+ @SliceHint List<String> hints) {
+ return addColor(color, subType, hints.toArray(new String[hints.size()]));
+ }
+
+ /**
+ * Add a color to the slice being constructed
+ * @param subType Optional template-specific type information
+ * @see {@link SliceItem#getSubType()}
+ */
+ public Builder addInt(int value, @Nullable String subType, @SliceHint String... hints) {
+ mItems.add(new SliceItem(value, SliceItem.FORMAT_INT, subType, hints));
return this;
}
@@ -386,9 +435,9 @@
* @param subType Optional template-specific type information
* @see {@link SliceItem#getSubType()}
*/
- public Builder addColor(int color, @Nullable String subType,
+ public Builder addInt(int value, @Nullable String subType,
@SliceHint List<String> hints) {
- return addColor(color, subType, hints.toArray(new String[hints.size()]));
+ return addInt(value, subType, hints.toArray(new String[hints.size()]));
}
/**
@@ -414,6 +463,32 @@
}
/**
+ * Add a bundle to the slice being constructed.
+ * <p>Expected to be used for support library extension, should not be used for general
+ * development
+ * @param subType Optional template-specific type information
+ * @see {@link SliceItem#getSubType()}
+ */
+ public Slice.Builder addBundle(Bundle bundle, @Nullable String subType,
+ @SliceHint String... hints) {
+ mItems.add(new SliceItem(bundle, SliceItem.FORMAT_BUNDLE, subType,
+ hints));
+ return this;
+ }
+
+ /**
+ * Add a bundle to the slice being constructed.
+ * <p>Expected to be used for support library extension, should not be used for general
+ * development
+ * @param subType Optional template-specific type information
+ * @see {@link SliceItem#getSubType()}
+ */
+ public Slice.Builder addBundle(Bundle bundle, @Nullable String subType,
+ @SliceHint List<String> hints) {
+ return addBundle(bundle, subType, hints.toArray(new String[hints.size()]));
+ }
+
+ /**
* Construct the slice.
*/
public Slice build() {
diff --git a/core/java/android/app/slice/SliceItem.java b/core/java/android/app/slice/SliceItem.java
index 8d81199..bcfd413 100644
--- a/core/java/android/app/slice/SliceItem.java
+++ b/core/java/android/app/slice/SliceItem.java
@@ -21,6 +21,7 @@
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.graphics.drawable.Icon;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -29,6 +30,8 @@
import com.android.internal.util.ArrayUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.List;
@@ -42,9 +45,10 @@
* <li>{@link #FORMAT_TEXT}</li>
* <li>{@link #FORMAT_IMAGE}</li>
* <li>{@link #FORMAT_ACTION}</li>
- * <li>{@link #FORMAT_COLOR}</li>
+ * <li>{@link #FORMAT_INT}</li>
* <li>{@link #FORMAT_TIMESTAMP}</li>
* <li>{@link #FORMAT_REMOTE_INPUT}</li>
+ * <li>{@link #FORMAT_BUNDLE}</li>
*
* The hints that a {@link SliceItem} are a set of strings which annotate
* the content. The hints that are guaranteed to be understood by the system
@@ -52,11 +56,22 @@
*/
public final class SliceItem implements Parcelable {
+ private static final String TAG = "SliceItem";
+
/**
* @hide
*/
- @StringDef({FORMAT_SLICE, FORMAT_TEXT, FORMAT_IMAGE, FORMAT_ACTION, FORMAT_COLOR,
- FORMAT_TIMESTAMP, FORMAT_REMOTE_INPUT})
+ @StringDef(prefix = { "FORMAT_" }, value = {
+ FORMAT_SLICE,
+ FORMAT_TEXT,
+ FORMAT_IMAGE,
+ FORMAT_ACTION,
+ FORMAT_INT,
+ FORMAT_TIMESTAMP,
+ FORMAT_REMOTE_INPUT,
+ FORMAT_BUNDLE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
public @interface SliceType {}
/**
@@ -79,7 +94,12 @@
*/
public static final String FORMAT_ACTION = "action";
/**
- * A {@link SliceItem} that contains a Color int.
+ * A {@link SliceItem} that contains an int.
+ */
+ public static final String FORMAT_INT = "int";
+ /**
+ * A {@link SliceItem} that contains an int.
+ * @deprecated to be removed
*/
public static final String FORMAT_COLOR = "color";
/**
@@ -90,6 +110,10 @@
* A {@link SliceItem} that contains a {@link RemoteInput}.
*/
public static final String FORMAT_REMOTE_INPUT = "input";
+ /**
+ * A {@link SliceItem} that contains a {@link Bundle}.
+ */
+ public static final String FORMAT_BUNDLE = "bundle";
/**
* @hide
@@ -128,20 +152,6 @@
}
/**
- * @hide
- */
- public void addHint(@Slice.SliceHint String hint) {
- mHints = ArrayUtils.appendElement(String.class, mHints, hint);
- }
-
- /**
- * @hide
- */
- public void removeHint(String hint) {
- ArrayUtils.removeElement(String.class, mHints, hint);
- }
-
- /**
* Get the format of this SliceItem.
* <p>
* The format will be one of the following types supported by the platform:
@@ -149,9 +159,10 @@
* <li>{@link #FORMAT_TEXT}</li>
* <li>{@link #FORMAT_IMAGE}</li>
* <li>{@link #FORMAT_ACTION}</li>
- * <li>{@link #FORMAT_COLOR}</li>
+ * <li>{@link #FORMAT_INT}</li>
* <li>{@link #FORMAT_TIMESTAMP}</li>
* <li>{@link #FORMAT_REMOTE_INPUT}</li>
+ * <li>{@link #FORMAT_BUNDLE}</li>
* @see #getSubType() ()
*/
public String getFormat() {
@@ -178,6 +189,13 @@
}
/**
+ * @return The parcelable held by this {@link #FORMAT_BUNDLE} SliceItem
+ */
+ public Bundle getBundle() {
+ return (Bundle) mObj;
+ }
+
+ /**
* @return The icon held by this {@link #FORMAT_IMAGE} SliceItem
*/
public Icon getIcon() {
@@ -206,7 +224,14 @@
}
/**
- * @return The color held by this {@link #FORMAT_COLOR} SliceItem
+ * @return The color held by this {@link #FORMAT_INT} SliceItem
+ */
+ public int getInt() {
+ return (Integer) mObj;
+ }
+
+ /**
+ * @deprecated to be removed.
*/
public int getColor() {
return (Integer) mObj;
@@ -216,7 +241,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;
@@ -299,6 +324,7 @@
case FORMAT_SLICE:
case FORMAT_IMAGE:
case FORMAT_REMOTE_INPUT:
+ case FORMAT_BUNDLE:
((Parcelable) obj).writeToParcel(dest, flags);
break;
case FORMAT_ACTION:
@@ -308,7 +334,7 @@
case FORMAT_TEXT:
TextUtils.writeToParcel((CharSequence) obj, dest, flags);
break;
- case FORMAT_COLOR:
+ case FORMAT_INT:
dest.writeInt((Integer) obj);
break;
case FORMAT_TIMESTAMP:
@@ -329,12 +355,14 @@
return new Pair<>(
PendingIntent.CREATOR.createFromParcel(in),
Slice.CREATOR.createFromParcel(in));
- case FORMAT_COLOR:
+ case FORMAT_INT:
return in.readInt();
case FORMAT_TIMESTAMP:
return in.readLong();
case FORMAT_REMOTE_INPUT:
return RemoteInput.CREATOR.createFromParcel(in);
+ case FORMAT_BUNDLE:
+ return Bundle.CREATOR.createFromParcel(in);
}
throw new RuntimeException("Unsupported type " + type);
}
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
new file mode 100644
index 0000000..f8e19c1
--- /dev/null
+++ b/core/java/android/app/slice/SliceManager.java
@@ -0,0 +1,131 @@
+/*
+ * 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.app.slice.ISliceListener.Stub;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.RemoteException;
+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));
+ }
+
+ /**
+ */
+ public void addSliceListener(Uri uri, SliceListener listener, SliceSpec[] specs) {
+ try {
+ mService.addSliceListener(uri, mContext.getPackageName(), listener.mStub, specs);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ */
+ public void removeSliceListener(Uri uri, SliceListener listener) {
+ try {
+ mService.removeSliceListener(uri, mContext.getPackageName(), listener.mStub);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ */
+ public void pinSlice(Uri uri, SliceSpec[] specs) {
+ try {
+ mService.pinSlice(mContext.getPackageName(), uri, specs);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ */
+ public void unpinSlice(Uri uri) {
+ try {
+ mService.unpinSlice(mContext.getPackageName(), uri);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ */
+ public boolean hasSliceAccess() {
+ try {
+ return mService.hasSliceAccess(mContext.getPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ */
+ public SliceSpec[] getPinnedSpecs(Uri uri) {
+ try {
+ return mService.getPinnedSpecs(uri, mContext.getPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ */
+ public abstract static class SliceListener {
+ private final Handler mHandler;
+
+ /**
+ */
+ public SliceListener() {
+ this(Handler.getMain());
+ }
+
+ /**
+ */
+ public SliceListener(Handler h) {
+ mHandler = h;
+ }
+
+ /**
+ */
+ public abstract void onSliceUpdated(Slice s);
+
+ private final ISliceListener.Stub mStub = new Stub() {
+ @Override
+ public void onSliceUpdated(Slice s) throws RemoteException {
+ mHandler.post(() -> SliceListener.this.onSliceUpdated(s));
+ }
+ };
+ }
+}
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index ac5365c..7dcd2fe 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -105,6 +105,14 @@
/**
* @hide
*/
+ public static final String METHOD_PIN = "pin";
+ /**
+ * @hide
+ */
+ public static final String METHOD_UNPIN = "unpin";
+ /**
+ * @hide
+ */
public static final String EXTRA_INTENT = "slice_intent";
/**
* @hide
@@ -143,6 +151,18 @@
}
/**
+ * @hide
+ */
+ public void onSlicePinned(Uri sliceUri) {
+ }
+
+ /**
+ * @hide
+ */
+ public void onSliceUnpinned(Uri sliceUri) {
+ }
+
+ /**
* This method must be overridden if an {@link IntentFilter} is specified on the SliceProvider.
* In that case, this method can be called and is expected to return a non-null Uri representing
* a slice. Otherwise this will throw {@link UnsupportedOperationException}.
@@ -221,6 +241,7 @@
getContext().enforceCallingPermission(permission.BIND_SLICE,
"Slice binding requires the permission BIND_SLICE");
Intent intent = extras.getParcelable(EXTRA_INTENT);
+ if (intent == null) return null;
Uri uri = onMapIntentToUri(intent);
List<SliceSpec> supportedSpecs = extras.getParcelableArrayList(EXTRA_SUPPORTED_SPECS);
Bundle b = new Bundle();
@@ -231,10 +252,62 @@
b.putParcelable(EXTRA_SLICE, null);
}
return b;
+ } else if (method.equals(METHOD_PIN)) {
+ Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+ if (!UserHandle.isSameApp(Binder.getCallingUid(), Process.myUid())) {
+ getContext().enforceUriPermission(uri, permission.BIND_SLICE,
+ permission.BIND_SLICE, Binder.getCallingPid(), Binder.getCallingUid(),
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+ "Slice binding requires the permission BIND_SLICE");
+ }
+ handlePinSlice(uri);
+ } else if (method.equals(METHOD_UNPIN)) {
+ Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+ if (!UserHandle.isSameApp(Binder.getCallingUid(), Process.myUid())) {
+ getContext().enforceUriPermission(uri, permission.BIND_SLICE,
+ permission.BIND_SLICE, Binder.getCallingPid(), Binder.getCallingUid(),
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+ "Slice binding requires the permission BIND_SLICE");
+ }
+ handleUnpinSlice(uri);
}
return super.call(method, arg, extras);
}
+ private void handlePinSlice(Uri sliceUri) {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ onSlicePinned(sliceUri);
+ } else {
+ CountDownLatch latch = new CountDownLatch(1);
+ Handler.getMain().post(() -> {
+ onSlicePinned(sliceUri);
+ latch.countDown();
+ });
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private void handleUnpinSlice(Uri sliceUri) {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ onSliceUnpinned(sliceUri);
+ } else {
+ CountDownLatch latch = new CountDownLatch(1);
+ Handler.getMain().post(() -> {
+ onSliceUnpinned(sliceUri);
+ latch.countDown();
+ });
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
private Slice handleBindSlice(Uri sliceUri, List<SliceSpec> supportedSpecs) {
if (Looper.myLooper() == Looper.getMainLooper()) {
return onBindSliceStrict(sliceUri, supportedSpecs);
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/core/java/android/app/slice/SliceSpec.aidl
similarity index 64%
copy from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
copy to core/java/android/app/slice/SliceSpec.aidl
index 4ccdea5..92e98b7 100644
--- a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
+++ b/core/java/android/app/slice/SliceSpec.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.app.slice;
-import android.telephony.SubscriptionInfo;
-
-oneway interface ISubscriptionListener {
- void onSubscriptionInfoChanged();
-}
-
+parcelable SliceSpec;
diff --git a/core/java/android/app/slice/SliceSpec.java b/core/java/android/app/slice/SliceSpec.java
index 433b67e..8cc0384 100644
--- a/core/java/android/app/slice/SliceSpec.java
+++ b/core/java/android/app/slice/SliceSpec.java
@@ -103,6 +103,11 @@
return mType.equals(other.mType) && mRevision == other.mRevision;
}
+ @Override
+ public String toString() {
+ return String.format("SliceSpec{%s,%d}", mType, mRevision);
+ }
+
public static final Creator<SliceSpec> CREATOR = new Creator<SliceSpec>() {
@Override
public SliceSpec createFromParcel(Parcel source) {
diff --git a/core/java/android/app/timezone/Callback.java b/core/java/android/app/timezone/Callback.java
index aea8038..e3840be 100644
--- a/core/java/android/app/timezone/Callback.java
+++ b/core/java/android/app/timezone/Callback.java
@@ -30,9 +30,14 @@
public abstract class Callback {
@Retention(RetentionPolicy.SOURCE)
- @IntDef({SUCCESS, ERROR_UNKNOWN_FAILURE, ERROR_INSTALL_BAD_DISTRO_STRUCTURE,
- ERROR_INSTALL_BAD_DISTRO_FORMAT_VERSION, ERROR_INSTALL_RULES_TOO_OLD,
- ERROR_INSTALL_VALIDATION_ERROR})
+ @IntDef(prefix = { "SUCCESS", "ERROR_" }, value = {
+ SUCCESS,
+ ERROR_UNKNOWN_FAILURE,
+ ERROR_INSTALL_BAD_DISTRO_STRUCTURE,
+ ERROR_INSTALL_BAD_DISTRO_FORMAT_VERSION,
+ ERROR_INSTALL_RULES_TOO_OLD,
+ ERROR_INSTALL_VALIDATION_ERROR
+ })
public @interface AsyncResultCode {}
/**
diff --git a/core/java/android/app/timezone/RulesManager.java b/core/java/android/app/timezone/RulesManager.java
index ad9b698..0a38eb9 100644
--- a/core/java/android/app/timezone/RulesManager.java
+++ b/core/java/android/app/timezone/RulesManager.java
@@ -69,7 +69,11 @@
private static final boolean DEBUG = false;
@Retention(RetentionPolicy.SOURCE)
- @IntDef({SUCCESS, ERROR_UNKNOWN_FAILURE, ERROR_OPERATION_IN_PROGRESS})
+ @IntDef(prefix = { "SUCCESS", "ERROR_" }, value = {
+ SUCCESS,
+ ERROR_UNKNOWN_FAILURE,
+ ERROR_OPERATION_IN_PROGRESS
+ })
public @interface ResultCode {}
/**
@@ -105,9 +109,9 @@
*/
public RulesState getRulesState() {
try {
- logDebug("sIRulesManager.getRulesState()");
+ logDebug("mIRulesManager.getRulesState()");
RulesState rulesState = mIRulesManager.getRulesState();
- logDebug("sIRulesManager.getRulesState() returned " + rulesState);
+ logDebug("mIRulesManager.getRulesState() returned " + rulesState);
return rulesState;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -131,7 +135,7 @@
ICallback iCallback = new CallbackWrapper(mContext, callback);
try {
- logDebug("sIRulesManager.requestInstall()");
+ logDebug("mIRulesManager.requestInstall()");
return mIRulesManager.requestInstall(distroFileDescriptor, checkToken, iCallback);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -151,7 +155,7 @@
public int requestUninstall(byte[] checkToken, Callback callback) {
ICallback iCallback = new CallbackWrapper(mContext, callback);
try {
- logDebug("sIRulesManager.requestUninstall()");
+ logDebug("mIRulesManager.requestUninstall()");
return mIRulesManager.requestUninstall(checkToken, iCallback);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -196,7 +200,7 @@
*/
public void requestNothing(byte[] checkToken, boolean succeeded) {
try {
- logDebug("sIRulesManager.requestNothing() with token=" + Arrays.toString(checkToken));
+ logDebug("mIRulesManager.requestNothing() with token=" + Arrays.toString(checkToken));
mIRulesManager.requestNothing(checkToken, succeeded);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/timezone/RulesState.java b/core/java/android/app/timezone/RulesState.java
index ec247eb..16309fa 100644
--- a/core/java/android/app/timezone/RulesState.java
+++ b/core/java/android/app/timezone/RulesState.java
@@ -63,11 +63,12 @@
public final class RulesState implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
+ @IntDef(prefix = { "STAGED_OPERATION_" }, value = {
STAGED_OPERATION_UNKNOWN,
STAGED_OPERATION_NONE,
STAGED_OPERATION_UNINSTALL,
- STAGED_OPERATION_INSTALL })
+ STAGED_OPERATION_INSTALL
+ })
private @interface StagedOperationType {}
/** Staged state could not be determined. */
@@ -80,10 +81,11 @@
public static final int STAGED_OPERATION_INSTALL = 3;
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
+ @IntDef(prefix = { "DISTRO_STATUS_" }, value = {
DISTRO_STATUS_UNKNOWN,
DISTRO_STATUS_NONE,
- DISTRO_STATUS_INSTALLED })
+ DISTRO_STATUS_INSTALLED
+ })
private @interface DistroStatus {}
/** The current distro status could not be determined. */
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/IStorageStatsManager.aidl b/core/java/android/app/usage/IStorageStatsManager.aidl
index 15e5ea5..7eacc89 100644
--- a/core/java/android/app/usage/IStorageStatsManager.aidl
+++ b/core/java/android/app/usage/IStorageStatsManager.aidl
@@ -22,6 +22,7 @@
/** {@hide} */
interface IStorageStatsManager {
boolean isQuotaSupported(String volumeUuid, String callingPackage);
+ boolean isReservedSupported(String volumeUuid, String callingPackage);
long getTotalBytes(String volumeUuid, String callingPackage);
long getFreeBytes(String volumeUuid, String callingPackage);
long getCacheBytes(String volumeUuid, String callingPackage);
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 4fbbdf2..f089c127 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -19,6 +19,8 @@
import android.app.usage.UsageEvents;
import android.content.pm.ParceledListSlice;
+import java.util.Map;
+
/**
* System private API for talking with the UsageStatsManagerService.
*
@@ -38,4 +40,6 @@
in String[] annotations, String action);
int getAppStandbyBucket(String packageName, String callingPackage, int userId);
void setAppStandbyBucket(String packageName, int bucket, int userId);
+ Map getAppStandbyBuckets(String callingPackage, int userId);
+ void setAppStandbyBuckets(in Map appBuckets, int userId);
}
diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java
index 222e9a0..2e44a63 100644
--- a/core/java/android/app/usage/NetworkStats.java
+++ b/core/java/android/app/usage/NetworkStats.java
@@ -129,7 +129,11 @@
*/
public static class Bucket {
/** @hide */
- @IntDef({STATE_ALL, STATE_DEFAULT, STATE_FOREGROUND})
+ @IntDef(prefix = { "STATE_" }, value = {
+ STATE_ALL,
+ STATE_DEFAULT,
+ STATE_FOREGROUND
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface State {}
@@ -164,7 +168,11 @@
public static final int UID_TETHERING = TrafficStats.UID_TETHERING;
/** @hide */
- @IntDef({METERED_ALL, METERED_NO, METERED_YES})
+ @IntDef(prefix = { "METERED_" }, value = {
+ METERED_ALL,
+ METERED_NO,
+ METERED_YES
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Metered {}
@@ -187,7 +195,11 @@
public static final int METERED_YES = 0x2;
/** @hide */
- @IntDef({ROAMING_ALL, ROAMING_NO, ROAMING_YES})
+ @IntDef(prefix = { "ROAMING_" }, value = {
+ ROAMING_ALL,
+ ROAMING_NO,
+ ROAMING_YES
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Roaming {}
diff --git a/core/java/android/app/usage/StorageStatsManager.java b/core/java/android/app/usage/StorageStatsManager.java
index 3d187ec..a86c27a 100644
--- a/core/java/android/app/usage/StorageStatsManager.java
+++ b/core/java/android/app/usage/StorageStatsManager.java
@@ -78,6 +78,16 @@
return isQuotaSupported(convert(uuid));
}
+ /** {@hide} */
+ @TestApi
+ public boolean isReservedSupported(@NonNull UUID storageUuid) {
+ try {
+ return mService.isReservedSupported(convert(storageUuid), mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Return the total size of the underlying physical media that is hosting
* this storage volume.
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 8200414..f04e907 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -110,10 +110,9 @@
public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
/** @hide */
- @IntDef(flag = true,
- value = {
- FLAG_IS_PACKAGE_INSTANT_APP,
- })
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+ FLAG_IS_PACKAGE_INSTANT_APP,
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface EventFlags {}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 3a3e16e..edb6a74 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, prefix = { "STANDBY_BUCKET_" }, 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,20 +320,52 @@
}
/**
- * @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.
+ * <p>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. One of STANDBY_BUCKET_* constants.
*/
+ 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
- * Changes the app standby state to the provided bucket.
+ * {@hide}
+ * Changes an app's standby bucket to the provided value. The caller can only set the standby
+ * bucket for a different app than itself.
+ * @param packageName the package name of the app to set the bucket for. A SecurityException
+ * will be thrown if the package name is that of the caller.
+ * @param bucket the standby bucket to set it to, which should be one of STANDBY_BUCKET_*.
+ * Setting a standby bucket outside of the range of STANDBY_BUCKET_ACTIVE to
+ * STANDBY_BUCKET_NEVER will result in a SecurityException.
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE)
@@ -275,6 +379,39 @@
/**
* {@hide}
+ * Returns the current standby bucket of every app that has a bucket assigned to it.
+ * The caller must hold the permission android.permission.PACKAGE_USAGE_STATS. The key of the
+ * returned Map is the package name and the value is the bucket assigned to the package.
+ * @see #getAppStandbyBucket()
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
+ public Map<String, Integer> getAppStandbyBuckets() {
+ try {
+ return (Map<String, Integer>) mService.getAppStandbyBuckets(
+ mContext.getOpPackageName(), mContext.getUserId());
+ } catch (RemoteException e) {
+ }
+ return Collections.EMPTY_MAP;
+ }
+
+ /**
+ * {@hide}
+ * Changes the app standby bucket for multiple apps at once. The Map is keyed by the package
+ * name and the value is one of STANDBY_BUCKET_*.
+ * @param appBuckets a map of package name to bucket value.
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE)
+ public void setAppStandbyBuckets(Map<String, Integer> appBuckets) {
+ try {
+ mService.setAppStandbyBuckets(appBuckets, mContext.getUserId());
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * {@hide}
* Temporarily whitelist the specified app for a short duration. This is to allow an app
* receiving a high priority message to be able to access the network and acquire wakelocks
* even if the device is in power-save mode or the app is currently considered inactive.
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/AppWidgetManagerInternal.java b/core/java/android/appwidget/AppWidgetManagerInternal.java
new file mode 100644
index 0000000..7ab3d8b
--- /dev/null
+++ b/core/java/android/appwidget/AppWidgetManagerInternal.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.appwidget;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.ArraySet;
+
+import java.util.Set;
+
+/**
+ * App widget manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class AppWidgetManagerInternal {
+
+ /**
+ * Gets the packages from which the uid hosts widgets.
+ *
+ * @param uid The potential host UID.
+ * @return Whether the UID hosts widgets from the package.
+ */
+ public abstract @Nullable ArraySet<String> getHostedWidgetPackages(int uid);
+}
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..3290d57 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(prefix = { "STATE_" }, value = {
+ 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}
@@ -357,10 +357,13 @@
"android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE";
/** @hide */
- @IntDef({SCAN_MODE_NONE, SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE_DISCOVERABLE})
+ @IntDef(prefix = { "SCAN_" }, value = {
+ 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 +399,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 +417,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 +451,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 +476,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 +573,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 +653,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 +667,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 +699,7 @@
synchronized (mLock) {
if (sPeriodicAdvertisingManager == null) {
- sPeriodicAdvertisingManager =
- new PeriodicAdvertisingManager(mManagerService);
+ sPeriodicAdvertisingManager = new PeriodicAdvertisingManager(mManagerService);
}
}
return sPeriodicAdvertisingManager;
@@ -709,7 +709,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 +731,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 +754,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 +787,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 +805,9 @@
return true;
}
- if (DBG) Log.d(TAG, "disableBLE(): Already disabled");
+ if (DBG) {
+ Log.d(TAG, "disableBLE(): Already disabled");
+ }
return false;
}
@@ -832,16 +844,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 +895,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 +941,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 +984,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 +1112,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 +1144,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 +1170,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 +1199,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 +1233,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 +1278,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 +1296,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 +1323,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 +1349,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 +1391,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 +1425,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 +1461,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 +1483,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 +1525,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 +1547,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 +1569,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 +1591,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 +1613,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 +1635,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 +1658,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 +1681,9 @@
* @hide
*/
public boolean isHardwareTrackingFiltersAvailable() {
- if (!getLeAccess()) return false;
+ if (!getLeAccess()) {
+ return false;
+ }
try {
IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
if (iGatt == null) {
@@ -1669,7 +1770,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 +1826,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 +1857,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 +1901,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 +1913,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 +2024,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 +2033,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 +2056,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 +2080,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 +2106,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 +2121,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 +2134,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 +2154,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 +2171,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 +2180,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 +2226,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 +2286,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 +2357,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 +2381,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 +2417,9 @@
}
public void onBrEdrDown() {
- if (VDBG) Log.i(TAG, "onBrEdrDown: " + mService);
+ if (VDBG) {
+ Log.i(TAG, "onBrEdrDown: " + mService);
+ }
}
};
@@ -2305,7 +2433,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 +2484,10 @@
* @hide
*/
public interface BluetoothStateChangeCallback {
- public void onBluetoothStateChange(boolean on);
+ /**
+ * @hide
+ */
+ void onBluetoothStateChange(boolean on);
}
/**
@@ -2363,8 +2496,7 @@
public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub {
private BluetoothStateChangeCallback mCallback;
- StateChangeCallbackWrapper(BluetoothStateChangeCallback
- callback) {
+ StateChangeCallbackWrapper(BluetoothStateChangeCallback callback) {
mCallback = callback;
}
@@ -2461,7 +2593,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 +2629,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 +2680,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 +2690,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 +2726,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 +2736,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/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index a1a9347..7944354 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -25,6 +25,10 @@
import android.os.RemoteException;
import android.util.Log;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
/**
* The Android Bluetooth API is not finalized, and *will* change. Use at your
* own risk.
@@ -48,11 +52,10 @@
*
* @hide
*/
-public class BluetoothPbap {
+public class BluetoothPbap implements BluetoothProfile {
private static final String TAG = "BluetoothPbap";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
+ private static final boolean DBG = false;
/**
* Intent used to broadcast the change in connection state of the PBAP
@@ -111,9 +114,9 @@
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
new IBluetoothStateChangeCallback.Stub() {
public void onBluetoothStateChange(boolean up) {
- if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ log("onBluetoothStateChange: up=" + up);
if (!up) {
- if (VDBG) Log.d(TAG, "Unbinding service...");
+ log("Unbinding service...");
synchronized (mConnection) {
try {
mService = null;
@@ -126,7 +129,7 @@
synchronized (mConnection) {
try {
if (mService == null) {
- if (VDBG) Log.d(TAG, "Binding service...");
+ log("Binding service...");
doBind();
}
} catch (Exception re) {
@@ -205,47 +208,60 @@
}
/**
- * Get the current state of the BluetoothPbap service.
- *
- * @return One of the STATE_ return codes, or {@link BluetoothProfile#STATE_DISCONNECTED}
- * if this proxy object is currently not connected to the Pbap service.
+ * {@inheritDoc}
*/
- public int getState() {
- if (VDBG) log("getState()");
+ @Override
+ public List<BluetoothDevice> getConnectedDevices() {
+ log("getConnectedDevices()");
final IBluetoothPbap service = mService;
- if (service != null) {
- try {
- return service.getState();
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
+ if (service == null) {
Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ try {
+ return service.getConnectedDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getConnectionState(BluetoothDevice device) {
+ log("getConnectionState: device=" + device);
+ final IBluetoothPbap service = mService;
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ try {
+ return service.getConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
}
return BluetoothProfile.STATE_DISCONNECTED;
}
/**
- * Get the currently connected remote Bluetooth device (PCE).
- *
- * @return The remote Bluetooth device, or null if not in connected or connecting state, or if
- * this proxy object is not connected to the Pbap service.
+ * {@inheritDoc}
*/
- public BluetoothDevice getClient() {
- if (VDBG) log("getClient()");
+ @Override
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ log("getDevicesMatchingConnectionStates: states=" + Arrays.toString(states));
final IBluetoothPbap service = mService;
- if (service != null) {
- try {
- return service.getClient();
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
+ if (service == null) {
Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
}
- return null;
+ try {
+ return service.getDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ return new ArrayList<BluetoothDevice>();
}
/**
@@ -253,20 +269,9 @@
* include connecting). Returns false if not connected, or if this proxy
* object is not currently connected to the Pbap service.
*/
+ // TODO: This is currently being used by SettingsLib and internal app.
public boolean isConnected(BluetoothDevice device) {
- if (VDBG) log("isConnected(" + device + ")");
- final IBluetoothPbap service = mService;
- if (service != null) {
- try {
- return service.isConnected(device);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- }
- return false;
+ return getConnectionState(device) == BluetoothAdapter.STATE_CONNECTED;
}
/**
@@ -274,47 +279,27 @@
* it may soon be made asynchronous. Returns false if this proxy object is
* not currently connected to the Pbap service.
*/
- public boolean disconnect() {
- if (DBG) log("disconnect()");
+ // TODO: This is currently being used by SettingsLib and will be used in the future.
+ // TODO: Must specify target device. Implement this in the service.
+ public boolean disconnect(BluetoothDevice device) {
+ log("disconnect()");
final IBluetoothPbap service = mService;
- if (service != null) {
- try {
- service.disconnect();
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
+ if (service == null) {
Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ try {
+ service.disconnect(device);
+ return true;
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
}
return false;
}
- /**
- * Check class bits for possible PBAP support.
- * This is a simple heuristic that tries to guess if a device with the
- * given class bits might support PBAP. It is not accurate for all
- * devices. It tries to err on the side of false positives.
- *
- * @return True if this device might support PBAP.
- */
- public static boolean doesClassMatchSink(BluetoothClass btClass) {
- // TODO optimize the rule
- switch (btClass.getDeviceClass()) {
- case BluetoothClass.Device.COMPUTER_DESKTOP:
- case BluetoothClass.Device.COMPUTER_LAPTOP:
- case BluetoothClass.Device.COMPUTER_SERVER:
- case BluetoothClass.Device.COMPUTER_UNCATEGORIZED:
- return true;
- default:
- return false;
- }
- }
-
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
- if (DBG) log("Proxy object connected");
+ log("Proxy object connected");
mService = IBluetoothPbap.Stub.asInterface(service);
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothPbap.this);
@@ -322,7 +307,7 @@
}
public void onServiceDisconnected(ComponentName className) {
- if (DBG) log("Proxy object disconnected");
+ log("Proxy object disconnected");
mService = null;
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected();
@@ -331,6 +316,8 @@
};
private static void log(String msg) {
- Log.d(TAG, msg);
+ if (DBG) {
+ Log.d(TAG, msg);
+ }
}
}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 46a230b..ebbc710 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -254,4 +254,28 @@
*/
public void onServiceDisconnected(int profile);
}
+
+ /**
+ * Convert an integer value of connection state into human readable string
+ *
+ * @param connectionState - One of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_CONNECTED}, or {@link #STATE_DISCONNECTED}
+ * @return a string representation of the connection state, STATE_UNKNOWN if the state
+ * is not defined
+ * @hide
+ */
+ static String getConnectionStateName(int connectionState) {
+ switch (connectionState) {
+ case STATE_DISCONNECTED:
+ return "STATE_DISCONNECTED";
+ case STATE_CONNECTING:
+ return "STATE_CONNECTING";
+ case STATE_CONNECTED:
+ return "STATE_CONNECTED";
+ case STATE_DISCONNECTING:
+ return "STATE_DISCONNECTING";
+ default:
+ return "STATE_UNKNOWN";
+ }
+ }
}
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingReport.java b/core/java/android/bluetooth/le/PeriodicAdvertisingReport.java
index 55c3a73..73a2e74 100644
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingReport.java
+++ b/core/java/android/bluetooth/le/PeriodicAdvertisingReport.java
@@ -71,7 +71,7 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mSyncHandle);
- dest.writeLong(mTxPower);
+ dest.writeInt(mTxPower);
dest.writeInt(mRssi);
dest.writeInt(mDataStatus);
if (mData != null) {
diff --git a/core/java/android/companion/DeviceFilter.java b/core/java/android/companion/DeviceFilter.java
index 9b4fdfd..10135a4 100644
--- a/core/java/android/companion/DeviceFilter.java
+++ b/core/java/android/companion/DeviceFilter.java
@@ -62,7 +62,11 @@
}
/** @hide */
- @IntDef({MEDIUM_TYPE_BLUETOOTH, MEDIUM_TYPE_BLUETOOTH_LE, MEDIUM_TYPE_WIFI})
+ @IntDef(prefix = { "MEDIUM_TYPE_" }, value = {
+ MEDIUM_TYPE_BLUETOOTH,
+ MEDIUM_TYPE_BLUETOOTH_LE,
+ MEDIUM_TYPE_WIFI
+ })
@Retention(RetentionPolicy.SOURCE)
@interface MediumType {}
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 9ccc552..8d2e141 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -335,7 +335,7 @@
public static final String EXTRA_HONORED_ARGS = "android.content.extra.HONORED_ARGS";
/** @hide */
- @IntDef(flag = false, value = {
+ @IntDef(flag = false, prefix = { "QUERY_SORT_DIRECTION_" }, value = {
QUERY_SORT_DIRECTION_ASCENDING,
QUERY_SORT_DIRECTION_DESCENDING
})
@@ -482,11 +482,10 @@
public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff;
/** @hide */
- @IntDef(flag = true,
- value = {
- NOTIFY_SYNC_TO_NETWORK,
- NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS
- })
+ @IntDef(flag = true, prefix = { "NOTIFY_" }, value = {
+ NOTIFY_SYNC_TO_NETWORK,
+ NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface NotifyFlags {}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 19e24ad..137c169 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -51,6 +51,7 @@
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.Looper;
import android.os.StatFs;
@@ -75,6 +76,7 @@
import java.io.InputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
/**
* Interface to global information about an application environment. This is
@@ -219,17 +221,16 @@
public static final int MODE_NO_LOCALIZED_COLLATORS = 0x0010;
/** @hide */
- @IntDef(flag = true,
- value = {
- BIND_AUTO_CREATE,
- BIND_DEBUG_UNBIND,
- BIND_NOT_FOREGROUND,
- BIND_ABOVE_CLIENT,
- BIND_ALLOW_OOM_MANAGEMENT,
- BIND_WAIVE_PRIORITY,
- BIND_IMPORTANT,
- BIND_ADJUST_WITH_ACTIVITY
- })
+ @IntDef(flag = true, prefix = { "BIND_" }, value = {
+ BIND_AUTO_CREATE,
+ BIND_DEBUG_UNBIND,
+ BIND_NOT_FOREGROUND,
+ BIND_ABOVE_CLIENT,
+ BIND_ALLOW_OOM_MANAGEMENT,
+ BIND_WAIVE_PRIORITY,
+ BIND_IMPORTANT,
+ BIND_ADJUST_WITH_ACTIVITY
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface BindServiceFlags {}
@@ -404,10 +405,9 @@
public static final int BIND_EXTERNAL_SERVICE = 0x80000000;
/** @hide */
- @IntDef(flag = true,
- value = {
- RECEIVER_VISIBLE_TO_INSTANT_APPS
- })
+ @IntDef(flag = true, prefix = { "RECEIVER_VISIBLE_" }, value = {
+ RECEIVER_VISIBLE_TO_INSTANT_APPS
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface RegisterReceiverFlags {}
@@ -462,6 +462,16 @@
public abstract Looper getMainLooper();
/**
+ * Return an {@link Executor} that will run enqueued tasks on the main
+ * thread associated with this context. This is the thread used to dispatch
+ * calls to application components (activities, services, etc).
+ */
+ public Executor getMainExecutor() {
+ // This is pretty inefficient, which is why ContextImpl overrides it
+ return new HandlerExecutor(new Handler(getMainLooper()));
+ }
+
+ /**
* Return the context of the single, global Application object of the
* current process. This generally should only be used if you need a
* Context whose lifecycle is separate from the current context, that is
@@ -754,6 +764,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 +2811,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 +2844,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.
@@ -2904,7 +2923,7 @@
@Nullable String profileFile, @Nullable Bundle arguments);
/** @hide */
- @StringDef({
+ @StringDef(suffix = { "_SERVICE" }, value = {
POWER_SERVICE,
WINDOW_SERVICE,
LAYOUT_INFLATER_SERVICE,
@@ -2938,7 +2957,7 @@
//@hide: LOWPAN_SERVICE,
//@hide: WIFI_RTT_SERVICE,
//@hide: ETHERNET_SERVICE,
- WIFI_RTT_SERVICE,
+ WIFI_RTT_RANGING_SERVICE,
NSD_SERVICE,
AUDIO_SERVICE,
FINGERPRINT_SERVICE,
@@ -3404,6 +3423,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.
*
@@ -3479,7 +3506,7 @@
* @see android.net.wifi.rtt.WifiRttManager
* @hide
*/
- public static final String WIFI_RTT2_SERVICE = "rttmanager2";
+ public static final String WIFI_RTT_RANGING_SERVICE = "rttmanager2";
/**
* Use with {@link #getSystemService} to retrieve a {@link
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 85acdc6..67de4fe 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -45,6 +45,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.concurrent.Executor;
/**
* Proxying implementation of Context that simply delegates all of its calls to
@@ -103,7 +104,12 @@
public Looper getMainLooper() {
return mBase.getMainLooper();
}
-
+
+ @Override
+ public Executor getMainExecutor() {
+ return mBase.getMainExecutor();
+ }
+
@Override
public Context getApplicationContext() {
return mBase.getApplicationContext();
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index bad452c..e940769 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
@@ -5665,11 +5690,14 @@
private static final int COPY_MODE_HISTORY = 2;
/** @hide */
- @IntDef(value = {COPY_MODE_ALL, COPY_MODE_FILTER, COPY_MODE_HISTORY})
+ @IntDef(prefix = { "COPY_MODE_" }, value = {
+ COPY_MODE_ALL,
+ COPY_MODE_FILTER,
+ COPY_MODE_HISTORY
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface CopyMode {}
-
/**
* Create an empty intent.
*/
@@ -8941,17 +8969,16 @@
}
/** @hide */
- @IntDef(flag = true,
- value = {
- FILL_IN_ACTION,
- FILL_IN_DATA,
- FILL_IN_CATEGORIES,
- FILL_IN_COMPONENT,
- FILL_IN_PACKAGE,
- FILL_IN_SOURCE_BOUNDS,
- FILL_IN_SELECTOR,
- FILL_IN_CLIP_DATA
- })
+ @IntDef(flag = true, prefix = { "FILL_IN_" }, value = {
+ FILL_IN_ACTION,
+ FILL_IN_DATA,
+ FILL_IN_CATEGORIES,
+ FILL_IN_COMPONENT,
+ FILL_IN_PACKAGE,
+ FILL_IN_SOURCE_BOUNDS,
+ FILL_IN_SELECTOR,
+ FILL_IN_CLIP_DATA
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface FillInFlags {}
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 f8cdce6..1461711 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -262,10 +262,10 @@
public static final int COLOR_MODE_HDR = 2;
/** @hide */
- @IntDef({
- COLOR_MODE_DEFAULT,
- COLOR_MODE_WIDE_COLOR_GAMUT,
- COLOR_MODE_HDR,
+ @IntDef(prefix = { "COLOR_MODE_" }, value = {
+ COLOR_MODE_DEFAULT,
+ COLOR_MODE_WIDE_COLOR_GAMUT,
+ COLOR_MODE_HDR,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ColorMode {}
@@ -492,7 +492,7 @@
public int flags;
/** @hide */
- @IntDef({
+ @IntDef(prefix = { "SCREEN_ORIENTATION_" }, value = {
SCREEN_ORIENTATION_UNSET,
SCREEN_ORIENTATION_UNSPECIFIED,
SCREEN_ORIENTATION_LANDSCAPE,
@@ -638,25 +638,24 @@
public int screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
/** @hide */
- @IntDef(flag = true,
- value = {
- CONFIG_MCC,
- CONFIG_MNC,
- CONFIG_LOCALE,
- CONFIG_TOUCHSCREEN,
- CONFIG_KEYBOARD,
- CONFIG_KEYBOARD_HIDDEN,
- CONFIG_NAVIGATION,
- CONFIG_ORIENTATION,
- CONFIG_SCREEN_LAYOUT,
- CONFIG_UI_MODE,
- CONFIG_SCREEN_SIZE,
- CONFIG_SMALLEST_SCREEN_SIZE,
- CONFIG_DENSITY,
- CONFIG_LAYOUT_DIRECTION,
- CONFIG_COLOR_MODE,
- CONFIG_FONT_SCALE,
- })
+ @IntDef(flag = true, prefix = { "CONFIG_" }, value = {
+ CONFIG_MCC,
+ CONFIG_MNC,
+ CONFIG_LOCALE,
+ CONFIG_TOUCHSCREEN,
+ CONFIG_KEYBOARD,
+ CONFIG_KEYBOARD_HIDDEN,
+ CONFIG_NAVIGATION,
+ CONFIG_ORIENTATION,
+ CONFIG_SCREEN_LAYOUT,
+ CONFIG_UI_MODE,
+ CONFIG_SCREEN_SIZE,
+ CONFIG_SMALLEST_SCREEN_SIZE,
+ CONFIG_DENSITY,
+ CONFIG_LAYOUT_DIRECTION,
+ CONFIG_COLOR_MODE,
+ CONFIG_FONT_SCALE,
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Config {}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index edb27cd..15e119b 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -26,6 +26,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Environment;
import android.os.Parcel;
import android.os.Parcelable;
@@ -594,6 +595,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 +621,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 +897,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
@@ -944,6 +953,13 @@
public int targetSandboxVersion;
/**
+ * The factory of this package, as specified by the <manifest>
+ * tag's {@link android.R.styleable#AndroidManifestApplication_appComponentFactory}
+ * attribute.
+ */
+ public String appComponentFactory;
+
+ /**
* The category of this app. Categories are used to cluster multiple apps
* together into meaningful groups, such as when summarizing battery,
* network, or disk usage. Apps should only define this value when they fit
@@ -1259,6 +1275,7 @@
targetSandboxVersion = orig.targetSandboxVersion;
classLoaderName = orig.classLoaderName;
splitClassLoaderNames = orig.splitClassLoaderNames;
+ appComponentFactory = orig.appComponentFactory;
}
public String toString() {
@@ -1315,7 +1332,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);
@@ -1331,6 +1348,7 @@
dest.writeStringArray(splitClassLoaderNames);
dest.writeInt(compileSdkVersion);
dest.writeString(compileSdkVersionCodename);
+ dest.writeString(appComponentFactory);
}
public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -1384,7 +1402,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();
@@ -1400,6 +1418,7 @@
splitClassLoaderNames = source.readStringArray();
compileSdkVersion = source.readInt();
compileSdkVersionCodename = source.readString();
+ appComponentFactory = source.readString();
}
/**
@@ -1569,6 +1588,16 @@
return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}
+ /** @hide */
+ public boolean isVendor() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+ }
+
+ /** @hide */
+ public boolean isTargetingDeprecatedSdkVersion() {
+ return targetSdkVersion < Build.VERSION.MIN_SUPPORTED_TARGET_SDK_INT;
+ }
+
/**
* 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/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..b4a7eec 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;
@@ -328,14 +343,13 @@
public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
/** @hide */
- @IntDef(flag = true,
- value = {
- FLAG_MATCH_DYNAMIC,
- FLAG_MATCH_PINNED,
- FLAG_MATCH_MANIFEST,
- FLAG_GET_KEY_FIELDS_ONLY,
- FLAG_MATCH_MANIFEST,
- })
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+ FLAG_MATCH_DYNAMIC,
+ FLAG_MATCH_PINNED,
+ FLAG_MATCH_MANIFEST,
+ FLAG_GET_KEY_FIELDS_ONLY,
+ FLAG_MATCH_MANIFEST,
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface QueryFlags {}
@@ -1365,7 +1379,10 @@
public static final int REQUEST_TYPE_APPWIDGET = 2;
/** @hide */
- @IntDef(value = {REQUEST_TYPE_SHORTCUT})
+ @IntDef(prefix = { "REQUEST_TYPE_" }, value = {
+ REQUEST_TYPE_SHORTCUT,
+ REQUEST_TYPE_APPWIDGET
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface RequestType {}
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index f8889b6..5a91e94 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -16,10 +16,14 @@
package android.content.pm;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Overall information about the contents of a package. This corresponds
* to all of the information collected from AndroidManifest.xml.
@@ -37,13 +41,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.
@@ -287,8 +334,29 @@
/** @hide */
public int overlayPriority;
- /** @hide */
- public boolean isStaticOverlay;
+ /**
+ * Flag for use with {@link #mOverlayFlags}. Marks the overlay as static, meaning it cannot
+ * be enabled/disabled at runtime.
+ */
+ static final int FLAG_OVERLAY_STATIC = 1 << 1;
+
+ /**
+ * Flag for use with {@link #mOverlayFlags}. Marks the overlay as trusted (not 3rd party).
+ */
+ static final int FLAG_OVERLAY_TRUSTED = 1 << 2;
+
+ @IntDef(flag = true, prefix = "FLAG_OVERLAY_", value = {
+ FLAG_OVERLAY_STATIC,
+ FLAG_OVERLAY_TRUSTED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface OverlayFlags {}
+
+ /**
+ * Modifiers that affect the state of this overlay. See {@link #FLAG_OVERLAY_STATIC},
+ * {@link #FLAG_OVERLAY_TRUSTED}.
+ */
+ @OverlayFlags int mOverlayFlags;
/**
* The user-visible SDK version (ex. 26) of the framework against which the application claims
@@ -316,6 +384,23 @@
public PackageInfo() {
}
+ /**
+ * Returns true if the package is a valid Runtime Overlay package.
+ * @hide
+ */
+ public boolean isOverlayPackage() {
+ return overlayTarget != null && (mOverlayFlags & FLAG_OVERLAY_TRUSTED) != 0;
+ }
+
+ /**
+ * Returns true if the package is a valid static Runtime Overlay package. Static overlays
+ * are not updatable outside of a system update and are safe to load in the system process.
+ * @hide
+ */
+ public boolean isStaticOverlayPackage() {
+ return overlayTarget != null && (mOverlayFlags & FLAG_OVERLAY_STATIC) != 0;
+ }
+
@Override
public String toString() {
return "PackageInfo{"
@@ -333,6 +418,7 @@
dest.writeString(packageName);
dest.writeStringArray(splitNames);
dest.writeInt(versionCode);
+ dest.writeInt(versionCodeMajor);
dest.writeString(versionName);
dest.writeInt(baseRevisionCode);
dest.writeIntArray(splitRevisionCodes);
@@ -366,8 +452,8 @@
dest.writeString(restrictedAccountType);
dest.writeString(requiredAccountType);
dest.writeString(overlayTarget);
- dest.writeInt(isStaticOverlay ? 1 : 0);
dest.writeInt(overlayPriority);
+ dest.writeInt(mOverlayFlags);
dest.writeInt(compileSdkVersion);
dest.writeString(compileSdkVersionCodename);
}
@@ -389,6 +475,7 @@
packageName = source.readString();
splitNames = source.createStringArray();
versionCode = source.readInt();
+ versionCodeMajor = source.readInt();
versionName = source.readString();
baseRevisionCode = source.readInt();
splitRevisionCodes = source.createIntArray();
@@ -420,8 +507,8 @@
restrictedAccountType = source.readString();
requiredAccountType = source.readString();
overlayTarget = source.readString();
- isStaticOverlay = source.readInt() != 0;
overlayPriority = source.readInt();
+ mOverlayFlags = source.readInt();
compileSdkVersion = source.readInt();
compileSdkVersionCodename = source.readString();
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 ebeaad7..2bbcfff 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -32,7 +32,6 @@
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
@@ -87,7 +86,8 @@
import android.util.SparseArray;
import android.util.TypedValue;
import android.util.apk.ApkSignatureSchemeV2Verifier;
-import android.util.jar.StrictJarFile;
+import android.util.apk.ApkSignatureVerifier;
+import android.util.apk.SignatureNotFoundException;
import android.view.Gravity;
import com.android.internal.R;
@@ -106,12 +106,10 @@
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Constructor;
-import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
@@ -129,8 +127,6 @@
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.zip.ZipEntry;
/**
* Parser for package files (APKs) on disk. This supports apps packaged either
@@ -173,7 +169,7 @@
// TODO: refactor "codePath" to "apkPath"
/** File name in an APK for the Android manifest. */
- private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
+ public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
/** Path prefix for apps on expanded storage */
private static final String MNT_EXPAND = "/mnt/expand/";
@@ -394,6 +390,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 +433,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 +474,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 +488,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 +500,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 +513,10 @@
this.extractNativeLibs = extractNativeLibs;
this.isolatedSplits = isolatedSplits;
}
+
+ public long getLongVersionCode() {
+ return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode);
+ }
}
/**
@@ -663,6 +667,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;
@@ -680,7 +685,15 @@
pi.requiredAccountType = p.mRequiredAccountType;
pi.overlayTarget = p.mOverlayTarget;
pi.overlayPriority = p.mOverlayPriority;
- pi.isStaticOverlay = p.mIsStaticOverlay;
+
+ if (p.mIsStaticOverlay) {
+ pi.mOverlayFlags |= PackageInfo.FLAG_OVERLAY_STATIC;
+ }
+
+ if (p.mTrustedOverlay) {
+ pi.mOverlayFlags |= PackageInfo.FLAG_OVERLAY_TRUSTED;
+ }
+
pi.compileSdkVersion = p.mCompileSdkVersion;
pi.compileSdkVersionCodename = p.mCompileSdkVersionCodename;
pi.firstInstallTime = firstInstallTime;
@@ -804,23 +817,6 @@
return pi;
}
- private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry entry)
- throws PackageParserException {
- InputStream is = null;
- try {
- // We must read the stream for the JarEntry to retrieve
- // its certificates.
- is = jarFile.getInputStream(entry);
- readFullyIgnoringContents(is);
- return jarFile.getCertificateChains(entry);
- } catch (IOException | RuntimeException e) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
- "Failed reading " + entry.getName() + " in " + jarFile, e);
- } finally {
- IoUtils.closeQuietly(is);
- }
- }
-
public static final int PARSE_MUST_BE_APK = 1 << 0;
public static final int PARSE_IGNORE_PROCESSES = 1 << 1;
public static final int PARSE_FORWARD_LOCK = 1 << 2;
@@ -1500,7 +1496,7 @@
pkg.mCertificates = certificates;
try {
- pkg.mSignatures = convertToSignatures(certificates);
+ pkg.mSignatures = ApkSignatureVerifier.convertToSignatures(certificates);
} catch (CertificateEncodingException e) {
// certificates weren't encoded properly; something went wrong
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
@@ -1563,157 +1559,46 @@
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
- // Try to verify the APK using APK Signature Scheme v2.
- boolean verified = false;
- {
- Certificate[][] allSignersCerts = null;
- Signature[] signatures = null;
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV2");
- allSignersCerts = ApkSignatureSchemeV2Verifier.verify(apkPath);
- signatures = convertToSignatures(allSignersCerts);
- // APK verified using APK Signature Scheme v2.
- verified = true;
- } catch (ApkSignatureSchemeV2Verifier.SignatureNotFoundException e) {
- // No APK Signature Scheme v2 signature found
- if ((parseFlags & PARSE_IS_EPHEMERAL) != 0) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ boolean untrusted = (parseFlags & PARSE_IS_SYSTEM_DIR) == 0;
+ int minSignatureScheme = ApkSignatureVerifier.VERSION_JAR_SIGNATURE_SCHEME;
+ if ((parseFlags & PARSE_IS_EPHEMERAL) != 0 || pkg.applicationInfo.isStaticSharedLibrary()) {
+ // must use v2 signing scheme
+ minSignatureScheme = ApkSignatureVerifier.VERSION_APK_SIGNATURE_SCHEME_V2;
+ }
+ try {
+ ApkSignatureVerifier.Result verified =
+ ApkSignatureVerifier.verify(apkPath, minSignatureScheme, untrusted);
+ if (pkg.mCertificates == null) {
+ pkg.mCertificates = verified.certs;
+ pkg.mSignatures = verified.sigs;
+ pkg.mSigningKeys = new ArraySet<>(verified.certs.length);
+ for (int i = 0; i < verified.certs.length; i++) {
+ Certificate[] signerCerts = verified.certs[i];
+ Certificate signerCert = signerCerts[0];
+ pkg.mSigningKeys.add(signerCert.getPublicKey());
+ }
+ } else {
+ if (!Signature.areExactMatch(pkg.mSignatures, verified.sigs)) {
+ throw new PackageParserException(
+ INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+ apkPath + " has mismatched certificates");
+ }
+ }
+ } catch (SignatureNotFoundException e) {
+ if ((parseFlags & PARSE_IS_EPHEMERAL) != 0) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No APK Signature Scheme v2 signature in ephemeral package " + apkPath,
e);
- }
- // Static shared libraries must use only the V2 signing scheme
- if (pkg.applicationInfo.isStaticSharedLibrary()) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "Static shared libs must use v2 signature scheme " + apkPath);
- }
- } catch (Exception e) {
- // APK Signature Scheme v2 signature was found but did not verify
+ }
+ if (pkg.applicationInfo.isStaticSharedLibrary()) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "Failed to collect certificates from " + apkPath
- + " using APK Signature Scheme v2",
- e);
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ "Static shared libs must use v2 signature scheme " + apkPath);
}
-
- if (verified) {
- if (pkg.mCertificates == null) {
- pkg.mCertificates = allSignersCerts;
- pkg.mSignatures = signatures;
- pkg.mSigningKeys = new ArraySet<>(allSignersCerts.length);
- for (int i = 0; i < allSignersCerts.length; i++) {
- Certificate[] signerCerts = allSignersCerts[i];
- Certificate signerCert = signerCerts[0];
- pkg.mSigningKeys.add(signerCert.getPublicKey());
- }
- } else {
- if (!Signature.areExactMatch(pkg.mSignatures, signatures)) {
- throw new PackageParserException(
- INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
- apkPath + " has mismatched certificates");
- }
- }
- // Not yet done, because we need to confirm that AndroidManifest.xml exists and,
- // if requested, that classes.dex exists.
- }
- }
-
- StrictJarFile jarFile = null;
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
- // Ignore signature stripping protections when verifying APKs from system partition.
- // For those APKs we only care about extracting signer certificates, and don't care
- // about verifying integrity.
- boolean signatureSchemeRollbackProtectionsEnforced =
- (parseFlags & PARSE_IS_SYSTEM_DIR) == 0;
- jarFile = new StrictJarFile(
- apkPath,
- !verified, // whether to verify JAR signature
- signatureSchemeRollbackProtectionsEnforced);
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-
- // Always verify manifest, regardless of source
- final ZipEntry manifestEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
- if (manifestEntry == null) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Package " + apkPath + " has no manifest");
- }
-
- // Optimization: early termination when APK already verified
- if (verified) {
- return;
- }
-
- // APK's integrity needs to be verified using JAR signature scheme.
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV1");
- final List<ZipEntry> toVerify = new ArrayList<>();
- toVerify.add(manifestEntry);
-
- // If we're parsing an untrusted package, verify all contents
- if ((parseFlags & PARSE_IS_SYSTEM_DIR) == 0) {
- final Iterator<ZipEntry> i = jarFile.iterator();
- while (i.hasNext()) {
- final ZipEntry entry = i.next();
-
- if (entry.isDirectory()) continue;
-
- final String entryName = entry.getName();
- if (entryName.startsWith("META-INF/")) continue;
- if (entryName.equals(ANDROID_MANIFEST_FILENAME)) continue;
-
- toVerify.add(entry);
- }
- }
-
- // Verify that entries are signed consistently with the first entry
- // we encountered. Note that for splits, certificates may have
- // already been populated during an earlier parse of a base APK.
- for (ZipEntry entry : toVerify) {
- final Certificate[][] entryCerts = loadCertificates(jarFile, entry);
- if (ArrayUtils.isEmpty(entryCerts)) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "Package " + apkPath + " has no certificates at entry "
- + entry.getName());
- }
- final Signature[] entrySignatures = convertToSignatures(entryCerts);
-
- if (pkg.mCertificates == null) {
- pkg.mCertificates = entryCerts;
- pkg.mSignatures = entrySignatures;
- pkg.mSigningKeys = new ArraySet<PublicKey>();
- for (int i=0; i < entryCerts.length; i++) {
- pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey());
- }
- } else {
- if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) {
- throw new PackageParserException(
- INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Package " + apkPath
- + " has mismatched certificates at entry "
- + entry.getName());
- }
- }
- }
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- } catch (GeneralSecurityException e) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
- "Failed to collect certificates from " + apkPath, e);
- } catch (IOException | RuntimeException e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "Failed to collect certificates from " + apkPath, e);
- } finally {
- closeQuietly(jarFile);
+ "No APK Signature Scheme v2 signature in package " + apkPath, e);
}
}
- private static Signature[] convertToSignatures(Certificate[][] certs)
- throws CertificateEncodingException {
- final Signature[] res = new Signature[certs.length];
- for (int i = 0; i < certs.length; i++) {
- res[i] = new Signature(certs[i]);
- }
- return res;
- }
-
private static AssetManager newConfiguredAssetManager() {
AssetManager assetManager = new AssetManager();
assetManager.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -1880,6 +1765,7 @@
int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
int versionCode = 0;
+ int versionCodeMajor = 0;
int revisionCode = 0;
boolean coreApp = false;
boolean debuggable = false;
@@ -1898,6 +1784,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")) {
@@ -1963,9 +1851,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);
}
/**
@@ -2086,8 +1974,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(
@@ -2912,7 +2803,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);
@@ -3733,6 +3624,11 @@
}
ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName,
str, outError);
+ String factory = sa.getNonResourceString(
+ com.android.internal.R.styleable.AndroidManifestApplication_appComponentFactory);
+ if (factory != null) {
+ ai.appComponentFactory = buildClassName(ai.packageName, factory, outError);
+ }
if (outError[0] == null) {
CharSequence pname;
@@ -3867,6 +3763,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();
@@ -3894,7 +3793,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);
@@ -5895,11 +5799,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;
@@ -5916,6 +5820,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;
@@ -6267,6 +6179,11 @@
}
/** @hide */
+ public boolean isVendor() {
+ return applicationInfo.isVendor();
+ }
+
+ /** @hide */
public boolean isPrivileged() {
return applicationInfo.isPrivilegedApp();
}
@@ -6385,7 +6302,7 @@
if (staticSharedLibName != null) {
staticSharedLibName = staticSharedLibName.intern();
}
- staticSharedLibVersion = dest.readInt();
+ staticSharedLibVersion = dest.readLong();
libraryNames = dest.createStringArrayList();
internStringArrayList(libraryNames);
usesLibraries = dest.createStringArrayList();
@@ -6399,8 +6316,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();
@@ -6418,6 +6335,7 @@
mAdoptPermissions = dest.createStringArrayList();
mAppMetaData = dest.readBundle();
mVersionCode = dest.readInt();
+ mVersionCodeMajor = dest.readInt();
mVersionName = dest.readString();
if (mVersionName != null) {
mVersionName = mVersionName.intern();
@@ -6540,7 +6458,7 @@
dest.writeParcelableList(childPackages, flags);
dest.writeString(staticSharedLibName);
- dest.writeInt(staticSharedLibVersion);
+ dest.writeLong(staticSharedLibVersion);
dest.writeStringList(libraryNames);
dest.writeStringList(usesLibraries);
dest.writeStringList(usesOptionalLibraries);
@@ -6551,7 +6469,7 @@
} else {
dest.writeInt(usesStaticLibraries.size());
dest.writeStringList(usesStaticLibraries);
- dest.writeIntArray(usesStaticLibrariesVersions);
+ dest.writeLongArray(usesStaticLibrariesVersions);
for (String[] usesStaticLibrariesCertDigest : usesStaticLibrariesCertDigests) {
dest.writeStringArray(usesStaticLibrariesCertDigest);
}
@@ -6564,6 +6482,7 @@
dest.writeStringList(mAdoptPermissions);
dest.writeBundle(mAppMetaData);
dest.writeInt(mVersionCode);
+ dest.writeInt(mVersionCodeMajor);
dest.writeString(mVersionName);
dest.writeString(mSharedUserId);
dest.writeInt(mSharedUserLabel);
@@ -7601,33 +7520,6 @@
sCompatibilityModeEnabled = compatibilityModeEnabled;
}
- private static AtomicReference<byte[]> sBuffer = new AtomicReference<byte[]>();
-
- public static long readFullyIgnoringContents(InputStream in) throws IOException {
- byte[] buffer = sBuffer.getAndSet(null);
- if (buffer == null) {
- buffer = new byte[4096];
- }
-
- int n = 0;
- int count = 0;
- while ((n = in.read(buffer, 0, buffer.length)) != -1) {
- count += n;
- }
-
- sBuffer.set(buffer);
- return count;
- }
-
- public static void closeQuietly(StrictJarFile jarFile) {
- if (jarFile != null) {
- try {
- jarFile.close();
- } catch (Exception ignored) {
- }
- }
- }
-
public static class PackageParserException extends Exception {
public final int error;
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 7588762..21bd7f0 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -17,6 +17,7 @@
package android.content.pm;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -144,6 +145,16 @@
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
+ */
+ @TestApi
+ 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 +242,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 +301,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..33bc951 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -36,13 +36,11 @@
public final class SharedLibraryInfo implements Parcelable {
/** @hide */
- @IntDef(
- flag = true,
- value = {
- TYPE_BUILTIN,
- TYPE_DYNAMIC,
- TYPE_STATIC,
- })
+ @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+ TYPE_BUILTIN,
+ TYPE_DYNAMIC,
+ TYPE_STATIC,
+ })
@Retention(RetentionPolicy.SOURCE)
@interface Type{}
@@ -73,8 +71,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 +87,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 +97,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 +121,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 +136,7 @@
*
* @return The version.
*/
- public @IntRange(from = -1) int getVersion() {
+ public @IntRange(from = -1) long getLongVersion() {
return mVersion;
}
@@ -192,7 +197,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/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 9ff0775..8839cf9 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -109,8 +109,7 @@
public static final int FLAG_SHADOW = 1 << 12;
/** @hide */
- @IntDef(flag = true,
- value = {
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
FLAG_DYNAMIC,
FLAG_PINNED,
FLAG_HAS_ICON_RES,
@@ -153,15 +152,14 @@
| CLONE_REMOVE_RES_NAMES;
/** @hide */
- @IntDef(flag = true,
- value = {
- CLONE_REMOVE_ICON,
- CLONE_REMOVE_INTENT,
- CLONE_REMOVE_NON_KEY_INFO,
- CLONE_REMOVE_RES_NAMES,
- CLONE_REMOVE_FOR_CREATOR,
- CLONE_REMOVE_FOR_LAUNCHER
- })
+ @IntDef(flag = true, prefix = { "CLONE_" }, value = {
+ CLONE_REMOVE_ICON,
+ CLONE_REMOVE_INTENT,
+ CLONE_REMOVE_NON_KEY_INFO,
+ CLONE_REMOVE_RES_NAMES,
+ CLONE_REMOVE_FOR_CREATOR,
+ CLONE_REMOVE_FOR_LAUNCHER
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface CloneFlags {}
@@ -212,7 +210,7 @@
public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103;
/** @hide */
- @IntDef(value = {
+ @IntDef(prefix = { "DISABLED_REASON_" }, value = {
DISABLED_REASON_NOT_DISABLED,
DISABLED_REASON_BY_APP,
DISABLED_REASON_APP_CHANGED,
@@ -220,7 +218,7 @@
DISABLED_REASON_BACKUP_NOT_SUPPORTED,
DISABLED_REASON_SIGNATURE_MISMATCH,
DISABLED_REASON_OTHER_RESTORE_ISSUE,
- })
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface DisabledReason{}
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/Configuration.java b/core/java/android/content/res/Configuration.java
index 26efda1..eb30979 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -781,25 +781,24 @@
public int seq;
/** @hide */
- @IntDef(flag = true,
- value = {
- NATIVE_CONFIG_MCC,
- NATIVE_CONFIG_MNC,
- NATIVE_CONFIG_LOCALE,
- NATIVE_CONFIG_TOUCHSCREEN,
- NATIVE_CONFIG_KEYBOARD,
- NATIVE_CONFIG_KEYBOARD_HIDDEN,
- NATIVE_CONFIG_NAVIGATION,
- NATIVE_CONFIG_ORIENTATION,
- NATIVE_CONFIG_DENSITY,
- NATIVE_CONFIG_SCREEN_SIZE,
- NATIVE_CONFIG_VERSION,
- NATIVE_CONFIG_SCREEN_LAYOUT,
- NATIVE_CONFIG_UI_MODE,
- NATIVE_CONFIG_SMALLEST_SCREEN_SIZE,
- NATIVE_CONFIG_LAYOUTDIR,
- NATIVE_CONFIG_COLOR_MODE,
- })
+ @IntDef(flag = true, prefix = { "NATIVE_CONFIG_" }, value = {
+ NATIVE_CONFIG_MCC,
+ NATIVE_CONFIG_MNC,
+ NATIVE_CONFIG_LOCALE,
+ NATIVE_CONFIG_TOUCHSCREEN,
+ NATIVE_CONFIG_KEYBOARD,
+ NATIVE_CONFIG_KEYBOARD_HIDDEN,
+ NATIVE_CONFIG_NAVIGATION,
+ NATIVE_CONFIG_ORIENTATION,
+ NATIVE_CONFIG_DENSITY,
+ NATIVE_CONFIG_SCREEN_SIZE,
+ NATIVE_CONFIG_VERSION,
+ NATIVE_CONFIG_SCREEN_LAYOUT,
+ NATIVE_CONFIG_UI_MODE,
+ NATIVE_CONFIG_SMALLEST_SCREEN_SIZE,
+ NATIVE_CONFIG_LAYOUTDIR,
+ NATIVE_CONFIG_COLOR_MODE,
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface NativeConfig {}
diff --git a/core/java/android/content/res/GradientColor.java b/core/java/android/content/res/GradientColor.java
index e465961..35ad503 100644
--- a/core/java/android/content/res/GradientColor.java
+++ b/core/java/android/content/res/GradientColor.java
@@ -75,9 +75,14 @@
private static final boolean DBG_GRADIENT = false;
- @IntDef({TILE_MODE_CLAMP, TILE_MODE_REPEAT, TILE_MODE_MIRROR})
+ @IntDef(prefix = { "TILE_MODE_" }, value = {
+ TILE_MODE_CLAMP,
+ TILE_MODE_REPEAT,
+ TILE_MODE_MIRROR
+ })
@Retention(RetentionPolicy.SOURCE)
private @interface GradientTileMode {}
+
private static final int TILE_MODE_CLAMP = 0;
private static final int TILE_MODE_REPEAT = 1;
private static final int TILE_MODE_MIRROR = 2;
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/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index 7049628..7866b52 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -17,6 +17,7 @@
package android.hardware;
import android.annotation.IntDef;
+import android.annotation.LongDef;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
@@ -41,7 +42,15 @@
public final class HardwareBuffer implements Parcelable, AutoCloseable {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({RGBA_8888, RGBA_FP16, RGBA_1010102, RGBX_8888, RGB_888, RGB_565, BLOB})
+ @IntDef(prefix = { "RGB", "BLOB" }, value = {
+ RGBA_8888,
+ RGBA_FP16,
+ RGBA_1010102,
+ RGBX_8888,
+ RGB_888,
+ RGB_565,
+ BLOB
+ })
public @interface Format {
}
@@ -70,7 +79,7 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {USAGE_CPU_READ_RARELY, USAGE_CPU_READ_OFTEN,
+ @LongDef(flag = true, value = {USAGE_CPU_READ_RARELY, USAGE_CPU_READ_OFTEN,
USAGE_CPU_WRITE_RARELY, USAGE_CPU_WRITE_OFTEN, USAGE_GPU_SAMPLED_IMAGE,
USAGE_GPU_COLOR_OUTPUT, USAGE_PROTECTED_CONTENT, USAGE_VIDEO_ENCODE,
USAGE_GPU_DATA_BUFFER, USAGE_SENSOR_DIRECT_DATA})
diff --git a/core/java/android/hardware/SensorAdditionalInfo.java b/core/java/android/hardware/SensorAdditionalInfo.java
index 7c876cf..5ff627f 100644
--- a/core/java/android/hardware/SensorAdditionalInfo.java
+++ b/core/java/android/hardware/SensorAdditionalInfo.java
@@ -68,8 +68,15 @@
*
* @hide
*/
- @IntDef({TYPE_FRAME_BEGIN, TYPE_FRAME_END, TYPE_UNTRACKED_DELAY, TYPE_INTERNAL_TEMPERATURE,
- TYPE_VEC3_CALIBRATION, TYPE_SENSOR_PLACEMENT, TYPE_SAMPLING})
+ @IntDef(prefix = { "TYPE_" }, value = {
+ TYPE_FRAME_BEGIN,
+ TYPE_FRAME_END,
+ TYPE_UNTRACKED_DELAY,
+ TYPE_INTERNAL_TEMPERATURE,
+ TYPE_VEC3_CALIBRATION,
+ TYPE_SENSOR_PLACEMENT,
+ TYPE_SAMPLING
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface AdditionalInfoType {}
diff --git a/core/java/android/hardware/SensorDirectChannel.java b/core/java/android/hardware/SensorDirectChannel.java
index 36607c9..214d3ec 100644
--- a/core/java/android/hardware/SensorDirectChannel.java
+++ b/core/java/android/hardware/SensorDirectChannel.java
@@ -40,8 +40,12 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {TYPE_MEMORY_FILE, TYPE_HARDWARE_BUFFER})
- public @interface MemoryType {};
+ @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+ TYPE_MEMORY_FILE,
+ TYPE_HARDWARE_BUFFER
+ })
+ public @interface MemoryType {}
+
/**
* Shared memory type ashmem, wrapped in MemoryFile object.
*
@@ -60,8 +64,13 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {RATE_STOP, RATE_NORMAL, RATE_FAST, RATE_VERY_FAST})
- public @interface RateLevel {};
+ @IntDef(flag = true, prefix = { "RATE_" }, value = {
+ RATE_STOP,
+ RATE_NORMAL,
+ RATE_FAST,
+ RATE_VERY_FAST
+ })
+ public @interface RateLevel {}
/**
* Sensor stopped (no event output).
diff --git a/core/java/android/hardware/camera2/CameraAccessException.java b/core/java/android/hardware/camera2/CameraAccessException.java
index f9b659c..d238797 100644
--- a/core/java/android/hardware/camera2/CameraAccessException.java
+++ b/core/java/android/hardware/camera2/CameraAccessException.java
@@ -16,7 +16,6 @@
package android.hardware.camera2;
-import android.annotation.NonNull;
import android.annotation.IntDef;
import android.util.AndroidException;
@@ -81,15 +80,16 @@
*/
public static final int CAMERA_DEPRECATED_HAL = 1000;
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(
- {CAMERA_IN_USE,
- MAX_CAMERAS_IN_USE,
- CAMERA_DISABLED,
- CAMERA_DISCONNECTED,
- CAMERA_ERROR})
- public @interface AccessError {};
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "CAMERA_", "MAX_CAMERAS_IN_USE" }, value = {
+ CAMERA_IN_USE,
+ MAX_CAMERAS_IN_USE,
+ CAMERA_DISABLED,
+ CAMERA_DISCONNECTED,
+ CAMERA_ERROR
+ })
+ public @interface AccessError {}
// Make the eclipse warning about serializable exceptions go away
private static final long serialVersionUID = 5630338637471475675L; // randomly generated
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/services/core/java/com/android/server/timezone/ClockHelper.java b/core/java/android/hardware/display/BrightnessConfiguration.aidl
similarity index 75%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/java/android/hardware/display/BrightnessConfiguration.aidl
index 353728a..5b6b464 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.aidl
@@ -14,12 +14,6 @@
* limitations under the License.
*/
-package com.android.server.timezone;
+package android.hardware.display;
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
-
- long currentTimestamp();
-}
+parcelable BrightnessConfiguration;
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
new file mode 100644
index 0000000..6c3be81
--- /dev/null
+++ b/core/java/android/hardware/display/BrightnessConfiguration.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 android.hardware.display;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Pair;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Arrays;
+
+/** @hide */
+public final class BrightnessConfiguration implements Parcelable {
+ private final float[] mLux;
+ private final float[] mNits;
+
+ private BrightnessConfiguration(float[] lux, float[] nits) {
+ mLux = lux;
+ mNits = nits;
+ }
+
+ /**
+ * Gets the base brightness as curve.
+ *
+ * The curve is returned as a pair of float arrays, the first representing all of the lux
+ * points of the brightness curve and the second representing all of the nits values of the
+ * brightness curve.
+ *
+ * @return the control points for the brightness curve.
+ */
+ public Pair<float[], float[]> getCurve() {
+ return Pair.create(Arrays.copyOf(mLux, mLux.length), Arrays.copyOf(mNits, mNits.length));
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeFloatArray(mLux);
+ dest.writeFloatArray(mNits);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("BrightnessConfiguration{[");
+ final int size = mLux.length;
+ for (int i = 0; i < size; i++) {
+ if (i != 0) {
+ sb.append(", ");
+ }
+ sb.append("(").append(mLux[i]).append(", ").append(mNits[i]).append(")");
+ }
+ sb.append("]}");
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+ result = result * 31 + Arrays.hashCode(mLux);
+ result = result * 31 + Arrays.hashCode(mNits);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof BrightnessConfiguration)) {
+ return false;
+ }
+ final BrightnessConfiguration other = (BrightnessConfiguration) o;
+ return Arrays.equals(mLux, other.mLux) && Arrays.equals(mNits, other.mNits);
+ }
+
+ public static final Creator<BrightnessConfiguration> CREATOR =
+ new Creator<BrightnessConfiguration>() {
+ public BrightnessConfiguration createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+ float[] lux = in.createFloatArray();
+ float[] nits = in.createFloatArray();
+ builder.setCurve(lux, nits);
+ return builder.build();
+ }
+
+ public BrightnessConfiguration[] newArray(int size) {
+ return new BrightnessConfiguration[size];
+ }
+ };
+
+ /**
+ * A builder class for {@link BrightnessConfiguration}s.
+ */
+ public static class Builder {
+ private float[] mCurveLux;
+ private float[] mCurveNits;
+
+ /**
+ * Sets the control points for the brightness curve.
+ *
+ * Brightness curves must have strictly increasing ambient brightness values in lux and
+ * monotonically increasing display brightness values in nits. In addition, the initial
+ * control point must be 0 lux.
+ *
+ * @throws IllegalArgumentException if the initial control point is not at 0 lux.
+ * @throws IllegalArgumentException if the lux levels are not strictly increasing.
+ * @throws IllegalArgumentException if the nit levels are not monotonically increasing.
+ */
+ public Builder setCurve(float[] lux, float[] nits) {
+ Preconditions.checkNotNull(lux);
+ Preconditions.checkNotNull(nits);
+ if (lux.length == 0 || nits.length == 0) {
+ throw new IllegalArgumentException("Lux and nits arrays must not be empty");
+ }
+ if (lux.length != nits.length) {
+ throw new IllegalArgumentException("Lux and nits arrays must be the same length");
+ }
+ if (lux[0] != 0) {
+ throw new IllegalArgumentException("Initial control point must be for 0 lux");
+ }
+ Preconditions.checkArrayElementsInRange(lux, 0, Float.MAX_VALUE, "lux");
+ Preconditions.checkArrayElementsInRange(nits, 0, Float.MAX_VALUE, "nits");
+ checkMonotonic(lux, true/*strictly increasing*/, "lux");
+ checkMonotonic(nits, false /*strictly increasing*/, "nits");
+ mCurveLux = lux;
+ mCurveNits = nits;
+ return this;
+ }
+
+ /**
+ * Builds the {@link BrightnessConfiguration}.
+ *
+ * A brightness curve <b>must</b> be set before calling this.
+ */
+ public BrightnessConfiguration build() {
+ if (mCurveLux == null || mCurveNits == null) {
+ throw new IllegalStateException("A curve must be set!");
+ }
+ return new BrightnessConfiguration(mCurveLux, mCurveNits);
+ }
+
+ private static void checkMonotonic(float[] vals, boolean strictlyIncreasing, String name) {
+ if (vals.length <= 1) {
+ return;
+ }
+ float prev = vals[0];
+ for (int i = 1; i < vals.length; i++) {
+ if (prev > vals[i] || prev == vals[i] && strictlyIncreasing) {
+ String condition = strictlyIncreasing ? "strictly increasing" : "monotonic";
+ throw new IllegalArgumentException(name + " values must be " + condition);
+ }
+ prev = vals[i];
+ }
+ }
+ }
+}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 8935745..7de667d 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;
@@ -25,6 +27,7 @@
import android.graphics.Point;
import android.media.projection.MediaProjection;
import android.os.Handler;
+import android.os.UserHandle;
import android.util.SparseArray;
import android.view.Display;
import android.view.Surface;
@@ -619,8 +622,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());
}
/**
@@ -631,6 +635,27 @@
}
/**
+ * Sets the global display brightness configuration.
+ *
+ * @hide
+ */
+ public void setBrightnessConfiguration(BrightnessConfiguration c) {
+ setBrightnessConfigurationForUser(c, UserHandle.myUserId());
+ }
+
+ /**
+ * Sets the global display brightness configuration for a specific user.
+ *
+ * Note this requires the INTERACT_ACROSS_USERS permission if setting the configuration for a
+ * user other than the one you're currently running as.
+ *
+ * @hide
+ */
+ public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId) {
+ mGlobal.setBrightnessConfigurationForUser(c, userId);
+ }
+
+ /**
* Listens for changes in available display devices.
*/
public interface DisplayListener {
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index d93d0e4..bf4cc1d 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();
}
@@ -486,6 +487,19 @@
}
}
+ /**
+ * Sets the global brightness configuration for a given user.
+ *
+ * @hide
+ */
+ public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId) {
+ try {
+ mDm.setBrightnessConfigurationForUser(c, userId);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
@Override
public void onDisplayEvent(int displayId, int event) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index b796cf9..8afae6e 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -18,6 +18,7 @@
import android.content.pm.ParceledListSlice;
import android.graphics.Point;
+import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.IDisplayManagerCallback;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.WifiDisplay;
@@ -84,9 +85,14 @@
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.
void setBrightness(int brightness);
+
+ // Sets the global brightness configuration for a given user. Requires
+ // CONFIGURE_DISPLAY_BRIGHTNESS, and INTERACT_ACROSS_USER if the user being configured is not
+ // the same as the calling user.
+ void setBrightnessConfigurationForUser(in BrightnessConfiguration c, int userId);
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index c531a89..1de8882 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -188,7 +188,11 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({SWITCH_STATE_UNKNOWN, SWITCH_STATE_OFF, SWITCH_STATE_ON})
+ @IntDef(prefix = { "SWITCH_STATE_" }, value = {
+ SWITCH_STATE_UNKNOWN,
+ SWITCH_STATE_OFF,
+ SWITCH_STATE_ON
+ })
public @interface SwitchState {}
/**
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..1d66dc6d 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -342,7 +342,17 @@
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public ContextHubTransaction<Void> loadNanoApp(
ContextHubInfo hubInfo, NanoAppBinary appBinary) {
- throw new UnsupportedOperationException("TODO: Implement this");
+ ContextHubTransaction<Void> transaction =
+ new ContextHubTransaction<>(ContextHubTransaction.TYPE_LOAD_NANOAPP);
+ IContextHubTransactionCallback callback = createTransactionCallback(transaction);
+
+ try {
+ mService.loadNanoAppOnHub(hubInfo.getId(), callback, appBinary);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ return transaction;
}
/**
@@ -357,7 +367,17 @@
*/
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public ContextHubTransaction<Void> unloadNanoApp(ContextHubInfo hubInfo, long nanoAppId) {
- throw new UnsupportedOperationException("TODO: Implement this");
+ ContextHubTransaction<Void> transaction =
+ new ContextHubTransaction<>(ContextHubTransaction.TYPE_UNLOAD_NANOAPP);
+ IContextHubTransactionCallback callback = createTransactionCallback(transaction);
+
+ try {
+ mService.unloadNanoAppFromHub(hubInfo.getId(), callback, nanoAppId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ return transaction;
}
/**
@@ -401,7 +421,17 @@
*/
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public ContextHubTransaction<List<NanoAppState>> queryNanoApps(ContextHubInfo hubInfo) {
- throw new UnsupportedOperationException("TODO: Implement this");
+ ContextHubTransaction<List<NanoAppState>> transaction =
+ new ContextHubTransaction<>(ContextHubTransaction.TYPE_QUERY_NANOAPPS);
+ IContextHubTransactionCallback callback = createQueryCallback(transaction);
+
+ try {
+ mService.queryNanoApps(hubInfo.getId(), callback);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ return transaction;
}
/**
@@ -456,6 +486,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 +541,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/hardware/location/ContextHubTransaction.java b/core/java/android/hardware/location/ContextHubTransaction.java
index a8569ef..2a66cbc 100644
--- a/core/java/android/hardware/location/ContextHubTransaction.java
+++ b/core/java/android/hardware/location/ContextHubTransaction.java
@@ -47,13 +47,15 @@
* Constants describing the type of a transaction through the Context Hub Service.
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
+ @IntDef(prefix = { "TYPE_" }, value = {
TYPE_LOAD_NANOAPP,
TYPE_UNLOAD_NANOAPP,
TYPE_ENABLE_NANOAPP,
TYPE_DISABLE_NANOAPP,
- TYPE_QUERY_NANOAPPS})
- public @interface Type {}
+ TYPE_QUERY_NANOAPPS
+ })
+ public @interface Type { }
+
public static final int TYPE_LOAD_NANOAPP = 0;
public static final int TYPE_UNLOAD_NANOAPP = 1;
public static final int TYPE_ENABLE_NANOAPP = 2;
@@ -64,7 +66,7 @@
* Constants describing the result of a transaction or request through the Context Hub Service.
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
+ @IntDef(prefix = { "TRANSACTION_" }, value = {
TRANSACTION_SUCCESS,
TRANSACTION_FAILED_UNKNOWN,
TRANSACTION_FAILED_BAD_PARAMS,
@@ -72,7 +74,9 @@
TRANSACTION_FAILED_PENDING,
TRANSACTION_FAILED_AT_HUB,
TRANSACTION_FAILED_TIMEOUT,
- TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE})
+ TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE,
+ TRANSACTION_FAILED_HAL_UNAVAILABLE
+ })
public @interface Result {}
public static final int TRANSACTION_SUCCESS = 0;
/**
@@ -103,6 +107,10 @@
* Failure mode when the transaction has failed internally at the service.
*/
public static final int TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE = 7;
+ /**
+ * Failure mode when the Context Hub HAL was not available.
+ */
+ public static final int TRANSACTION_FAILED_HAL_UNAVAILABLE = 8;
/**
* A class describing the response for a ContextHubTransaction.
@@ -189,6 +197,30 @@
}
/**
+ * Converts a transaction type to a human-readable string
+ *
+ * @param type the type of a transaction
+ * @param upperCase {@code true} if upper case the first letter, {@code false} otherwise
+ * @return a string describing the transaction
+ */
+ public static String typeToString(@Type int type, boolean upperCase) {
+ switch (type) {
+ case ContextHubTransaction.TYPE_LOAD_NANOAPP:
+ return upperCase ? "Load" : "load";
+ case ContextHubTransaction.TYPE_UNLOAD_NANOAPP:
+ return upperCase ? "Unload" : "unload";
+ case ContextHubTransaction.TYPE_ENABLE_NANOAPP:
+ return upperCase ? "Enable" : "enable";
+ case ContextHubTransaction.TYPE_DISABLE_NANOAPP:
+ return upperCase ? "Disable" : "disable";
+ case ContextHubTransaction.TYPE_QUERY_NANOAPPS:
+ return upperCase ? "Query" : "query";
+ default:
+ return upperCase ? "Unknown" : "unknown";
+ }
+ }
+
+ /**
* @return the type of the transaction
*/
@Type
@@ -239,7 +271,7 @@
* A transaction can be invalidated if the process owning the transaction is no longer active
* and the reference to this object is lost.
*
- * This method or {@link #setCallbackOnCompletecan(ContextHubTransaction.Callback)} can only be
+ * This method or {@link #setCallbackOnComplete(ContextHubTransaction.Callback)} can only be
* invoked once, or an IllegalStateException will be thrown.
*
* @param callback the callback to be invoked upon completion
diff --git a/core/java/android/print/IPrintClient.aidl b/core/java/android/hardware/location/IContextHubClient.aidl
similarity index 63%
rename from core/java/android/print/IPrintClient.aidl
rename 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..628ebc7 100644
--- a/core/java/android/hardware/location/IContextHubService.aidl
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -17,39 +17,59 @@
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.NanoAppBinary;
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;
+import android.hardware.location.IContextHubTransactionCallback;
/**
* @hide
*/
interface IContextHubService {
- // register a callback to receive messages
+ // Registers a callback to receive messages
int registerCallback(in IContextHubCallback callback);
// Gets a list of available context hub handles
int[] getContextHubHandles();
- // Get the properties of a hub
+ // Gets the properties of a hub
ContextHubInfo getContextHubInfo(int contextHubHandle);
- // Load a nanoapp on a specified context hub
+ // Loads a nanoapp at the specified hub (old API)
int loadNanoApp(int hubHandle, in NanoApp app);
- // Unload a nanoapp instance
+ // Unloads a nanoapp given its instance ID (old API)
int unloadNanoApp(int nanoAppInstanceHandle);
- // get information about a nanoAppInstance
+ // Gets the NanoAppInstanceInfo of a nanoapp give its instance ID
NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle);
- // find all nanoApp instances matching some filter
+ // Finds all nanoApp instances matching some filter
int[] findNanoAppOnHub(int hubHandle, in NanoAppFilter filter);
- // send a message to a nanoApp
+ // Sends 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);
+
+ // Loads a nanoapp at the specified hub (new API)
+ void loadNanoAppOnHub(
+ int contextHubId, in IContextHubTransactionCallback transactionCallback,
+ in NanoAppBinary nanoAppBinary);
+
+ // Unloads a nanoapp on a specified context hub (new API)
+ void unloadNanoAppFromHub(
+ int contextHubId, in IContextHubTransactionCallback transactionCallback,
+ long nanoAppId);
+
+ // Queries for a list of nanoapps
+ void queryNanoApps(int contextHubId, in IContextHubTransactionCallback transactionCallback);
}
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/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index 2623830..b7e6b66 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -16,9 +16,7 @@
package android.hardware.location;
-
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -26,29 +24,42 @@
import libcore.util.EmptyArray;
/**
+ * Describes an instance of a nanoapp, used by the internal state manged by ContextHubService.
+ *
+ * TODO(b/69270990) Remove this class once the old API is deprecated.
+ * TODO(b/70624255) Clean up toString() by removing unnecessary fields
+ *
* @hide
*/
@SystemApi
public class NanoAppInstanceInfo {
- private String mPublisher;
- private String mName;
+ private static final String PRE_LOADED_GENERIC_UNKNOWN = "Preloaded app, unknown";
+ private String mPublisher = PRE_LOADED_GENERIC_UNKNOWN;
+ private String mName = PRE_LOADED_GENERIC_UNKNOWN;
+ private int mHandle;
private long mAppId;
private int mAppVersion;
-
- private int mNeededReadMemBytes;
- private int mNeededWriteMemBytes;
- private int mNeededExecMemBytes;
-
- private int[] mNeededSensors;
- private int[] mOutputEvents;
-
private int mContexthubId;
- private int mHandle;
+
+ private int mNeededReadMemBytes = 0;
+ private int mNeededWriteMemBytes = 0;
+ private int mNeededExecMemBytes = 0;
+
+ private int[] mNeededSensors = EmptyArray.INT;
+ private int[] mOutputEvents = EmptyArray.INT;
public NanoAppInstanceInfo() {
- mNeededSensors = EmptyArray.INT;
- mOutputEvents = EmptyArray.INT;
+ }
+
+ /**
+ * @hide
+ */
+ public NanoAppInstanceInfo(int handle, long appId, int appVersion, int contextHubId) {
+ mHandle = handle;
+ mAppId = appId;
+ mAppVersion = appVersion;
+ mContexthubId = contextHubId;
}
/**
@@ -60,18 +71,6 @@
return mPublisher;
}
-
- /**
- * set the publisher name for the app
- *
- * @param publisher - name of the publisher
- *
- * @hide
- */
- public void setPublisher(String publisher) {
- mPublisher = publisher;
- }
-
/**
* get the name of the app
*
@@ -82,17 +81,6 @@
}
/**
- * set the name of the app
- *
- * @param name - name of the app
- *
- * @hide
- */
- public void setName(String name) {
- mName = name;
- }
-
- /**
* Get the application identifier
*
* @return int - application identifier
@@ -102,17 +90,6 @@
}
/**
- * Set the application identifier
- *
- * @param appId - application identifier
- *
- * @hide
- */
- public void setAppId(long appId) {
- mAppId = appId;
- }
-
- /**
* Get the application version
*
* NOTE: There is a race condition where shortly after loading, this
@@ -127,17 +104,6 @@
}
/**
- * Set the application version
- *
- * @param appVersion - version of the app
- *
- * @hide
- */
- public void setAppVersion(int appVersion) {
- mAppVersion = appVersion;
- }
-
- /**
* Get the read memory needed by the app
*
* @return int - readable memory needed in bytes
@@ -147,17 +113,6 @@
}
/**
- * Set the read memory needed by the app
- *
- * @param neededReadMemBytes - readable Memory needed in bytes
- *
- * @hide
- */
- public void setNeededReadMemBytes(int neededReadMemBytes) {
- mNeededReadMemBytes = neededReadMemBytes;
- }
-
- /**
* get writable memory needed by the app
*
* @return int - writable memory needed by the app
@@ -167,18 +122,6 @@
}
/**
- * set writable memory needed by the app
- *
- * @param neededWriteMemBytes - writable memory needed by the
- * app
- *
- * @hide
- */
- public void setNeededWriteMemBytes(int neededWriteMemBytes) {
- mNeededWriteMemBytes = neededWriteMemBytes;
- }
-
- /**
* get executable memory needed by the app
*
* @return int - executable memory needed by the app
@@ -188,18 +131,6 @@
}
/**
- * set executable memory needed by the app
- *
- * @param neededExecMemBytes - executable memory needed by the
- * app
- *
- * @hide
- */
- public void setNeededExecMemBytes(int neededExecMemBytes) {
- mNeededExecMemBytes = neededExecMemBytes;
- }
-
- /**
* Get the sensors needed by this app
*
* @return int[] all the required sensors needed by this app
@@ -210,17 +141,6 @@
}
/**
- * set the sensors needed by this app
- *
- * @param neededSensors - all the sensors needed by this app
- *
- * @hide
- */
- public void setNeededSensors(@Nullable int[] neededSensors) {
- mNeededSensors = neededSensors != null ? neededSensors : EmptyArray.INT;
- }
-
- /**
* get the events generated by this app
*
* @return all the events that can be generated by this app
@@ -231,18 +151,6 @@
}
/**
- * set the output events that can be generated by this app
- *
- * @param outputEvents - the events that may be generated by
- * this app
- *
- * @hide
- */
- public void setOutputEvents(@Nullable int[] outputEvents) {
- mOutputEvents = outputEvents != null ? outputEvents : EmptyArray.INT;
- }
-
- /**
* get the context hub identifier
*
* @return int - system unique hub identifier
@@ -252,17 +160,6 @@
}
/**
- * set the context hub identifier
- *
- * @param contexthubId - system wide unique identifier
- *
- * @hide
- */
- public void setContexthubId(int contexthubId) {
- mContexthubId = contexthubId;
- }
-
- /**
* get a handle to the nano app instance
*
* @return int - handle to this instance
@@ -271,18 +168,6 @@
return mHandle;
}
- /**
- * set the handle for an app instance
- *
- * @param handle - handle to this instance
- *
- * @hide
- */
- public void setHandle(int handle) {
- mHandle = handle;
- }
-
-
private NanoAppInstanceInfo(Parcel in) {
mPublisher = in.readString();
mName = in.readString();
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 223ed73..02b1c65 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -392,7 +392,7 @@
mWindow.setToken(token);
}
}
-
+
/**
* {@inheritDoc}
*
@@ -1064,7 +1064,89 @@
}
return mInputConnection;
}
-
+
+ /**
+ * Force switch to a new input method component. This can only be called
+ * from an application or a service which has a token of the currently active input method.
+ * @param id The unique identifier for the new input method to be switched to.
+ */
+ public void setInputMethod(String id) {
+ mImm.setInputMethodInternal(mToken, id);
+ }
+
+ /**
+ * Force switch to a new input method and subtype. This can only be called
+ * from an application or a service which has a token of the currently active input method.
+ * @param id The unique identifier for the new input method to be switched to.
+ * @param subtype The new subtype of the new input method to be switched to.
+ */
+ public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype) {
+ mImm.setInputMethodAndSubtypeInternal(mToken, id, subtype);
+ }
+
+ /**
+ * Close/hide the input method's soft input area, so the user no longer
+ * sees it or can interact with it. This can only be called
+ * from the currently active input method, as validated by the given token.
+ *
+ * @param flags Provides additional operating flags. Currently may be
+ * 0 or have the {@link InputMethodManager#HIDE_IMPLICIT_ONLY},
+ * {@link InputMethodManager#HIDE_NOT_ALWAYS} bit set.
+ */
+ public void hideSoftInputFromInputMethod(int flags) {
+ mImm.hideSoftInputFromInputMethodInternal(mToken, flags);
+ }
+
+ /**
+ * Show the input method's soft input area, so the user
+ * sees the input method window and can interact with it.
+ * This can only be called from the currently active input method,
+ * as validated by the given token.
+ *
+ * @param flags Provides additional operating flags. Currently may be
+ * 0 or have the {@link InputMethodManager#SHOW_IMPLICIT} or
+ * {@link InputMethodManager#SHOW_FORCED} bit set.
+ */
+ public void showSoftInputFromInputMethod(int flags) {
+ mImm.showSoftInputFromInputMethodInternal(mToken, flags);
+ }
+
+ /**
+ * Force switch to the last used input method and subtype. If the last input method didn't have
+ * any subtypes, the framework will simply switch to the last input method with no subtype
+ * specified.
+ * @return true if the current input method and subtype was successfully switched to the last
+ * used input method and subtype.
+ */
+ public boolean switchToLastInputMethod() {
+ return mImm.switchToLastInputMethodInternal(mToken);
+ }
+
+ /**
+ * Force switch to the next input method and subtype. If there is no IME enabled except
+ * current IME and subtype, do nothing.
+ * @param onlyCurrentIme if true, the framework will find the next subtype which
+ * belongs to the current IME
+ * @return true if the current input method and subtype was successfully switched to the next
+ * input method and subtype.
+ */
+ public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
+ return mImm.switchToNextInputMethodInternal(mToken, onlyCurrentIme);
+ }
+
+ /**
+ * Returns true if the current IME needs to offer the users ways to switch to a next input
+ * method (e.g. a globe key.).
+ * When an IME sets supportsSwitchingToNextInputMethod and this method returns true,
+ * the IME has to offer ways to to invoke {@link #switchToNextInputMethod} accordingly.
+ * <p> Note that the system determines the most appropriate next input method
+ * and subtype in order to provide the consistent user experience in switching
+ * between IMEs and subtypes.
+ */
+ public boolean shouldOfferSwitchingToNextInputMethod() {
+ return mImm.shouldOfferSwitchingToNextInputMethodInternal(mToken);
+ }
+
public boolean getCurrentInputStarted() {
return mInputStarted;
}
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/OWNERS b/core/java/android/net/OWNERS
index d1ce60e..6758d95 100644
--- a/core/java/android/net/OWNERS
+++ b/core/java/android/net/OWNERS
@@ -1,6 +1,7 @@
ek@google.com
hugobenichi@google.com
jsharkey@android.com
+jchalard@google.com
lorenzo@google.com
satk@google.com
silberst@google.com
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/DefaultNetworkEvent.java b/core/java/android/net/metrics/DefaultNetworkEvent.java
index 8ff8e4f..6f383b4 100644
--- a/core/java/android/net/metrics/DefaultNetworkEvent.java
+++ b/core/java/android/net/metrics/DefaultNetworkEvent.java
@@ -74,7 +74,7 @@
j.add("final_score=" + finalScore);
}
j.add(String.format("duration=%.0fs", durationMs / 1000.0));
- j.add(String.format("validation=%4.1f%%", (validatedMs * 100.0) / durationMs));
+ j.add(String.format("validation=%04.1f%%", (validatedMs * 100.0) / durationMs));
return j.toString();
}
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 811091e..2e9eeb1 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1180,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 {
@@ -6742,7 +6742,7 @@
/** Dump #STATS_SINCE_CHARGED batterystats data to a proto. @hide */
public void dumpProtoLocked(Context context, FileDescriptor fd, List<ApplicationInfo> apps,
- int flags, long historyStart) {
+ int flags) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
final long bToken = proto.start(BatteryStatsServiceDumpProto.BATTERYSTATS);
prepareForDumpLocked();
@@ -6752,13 +6752,7 @@
proto.write(BatteryStatsProto.START_PLATFORM_VERSION, getStartPlatformVersion());
proto.write(BatteryStatsProto.END_PLATFORM_VERSION, getEndPlatformVersion());
- long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
-
- if ((flags & (DUMP_INCLUDE_HISTORY | DUMP_HISTORY_ONLY)) != 0) {
- if (startIteratingHistoryLocked()) {
- // TODO: implement dumpProtoHistoryLocked(proto);
- }
- }
+ // History intentionally not included in proto dump.
if ((flags & (DUMP_HISTORY_ONLY | DUMP_DAILY_ONLY)) == 0) {
final BatteryStatsHelper helper = new BatteryStatsHelper(context, false,
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 02c7bd6..48f5684 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -117,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() {
@@ -215,13 +221,31 @@
public static final String SDK = getString("ro.build.version.sdk");
/**
- * The user-visible SDK version of the framework; its possible
- * values are defined in {@link Build.VERSION_CODES}.
+ * The SDK version of the software currently running on this hardware
+ * device. This value never changes while a device is booted, but it may
+ * increase when the hardware manufacturer provides an OTA update.
+ * <p>
+ * Possible values are defined in {@link Build.VERSION_CODES}.
+ *
+ * @see #FIRST_SDK_INT
*/
public static final int SDK_INT = SystemProperties.getInt(
"ro.build.version.sdk", 0);
/**
+ * The SDK version of the software that <em>initially</em> shipped on
+ * this hardware device. It <em>never</em> changes during the lifetime
+ * of the device, even when {@link #SDK_INT} increases due to an OTA
+ * update.
+ * <p>
+ * Possible values are defined in {@link Build.VERSION_CODES}.
+ *
+ * @see #SDK_INT
+ */
+ public static final int FIRST_SDK_INT = SystemProperties
+ .getInt("ro.product.first_api_level", 0);
+
+ /**
* The developer preview revision of a prerelease SDK. This value will always
* be <code>0</code> on production platform builds/devices.
*
@@ -264,6 +288,14 @@
* @hide
*/
public static final int RESOURCES_SDK_INT = SDK_INT + ACTIVE_CODENAMES.length;
+
+ /**
+ * The current lowest supported value of app target SDK. Applications targeting
+ * lower values will fail to install and run. Its possible values are defined
+ * in {@link Build.VERSION_CODES}.
+ */
+ public static final int MIN_SUPPORTED_TARGET_SDK_INT = SystemProperties.getInt(
+ "ro.build.version.min_supported_target_sdk", 0);
}
/**
@@ -937,7 +969,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/HandlerExecutor.java b/core/java/android/os/HandlerExecutor.java
new file mode 100644
index 0000000..416b24b
--- /dev/null
+++ b/core/java/android/os/HandlerExecutor.java
@@ -0,0 +1,45 @@
+/*
+ * 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 android.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * An adapter {@link Executor} that posts all executed tasks onto the given
+ * {@link Handler}.
+ *
+ * @hide
+ */
+public class HandlerExecutor implements Executor {
+ private final Handler mHandler;
+
+ public HandlerExecutor(@NonNull Handler handler) {
+ mHandler = Preconditions.checkNotNull(handler);
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ if (!mHandler.post(command)) {
+ throw new RejectedExecutionException(mHandler + " is shutting down");
+ }
+ }
+}
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
index aad202e..eae7d70 100644
--- a/core/java/android/os/HardwarePropertiesManager.java
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -40,9 +40,11 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
- DEVICE_TEMPERATURE_CPU, DEVICE_TEMPERATURE_GPU, DEVICE_TEMPERATURE_BATTERY,
- DEVICE_TEMPERATURE_SKIN
+ @IntDef(prefix = { "DEVICE_TEMPERATURE_" }, value = {
+ DEVICE_TEMPERATURE_CPU,
+ DEVICE_TEMPERATURE_GPU,
+ DEVICE_TEMPERATURE_BATTERY,
+ DEVICE_TEMPERATURE_SKIN
})
public @interface DeviceTemperatureType {}
@@ -50,9 +52,11 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
- TEMPERATURE_CURRENT, TEMPERATURE_THROTTLING, TEMPERATURE_SHUTDOWN,
- TEMPERATURE_THROTTLING_BELOW_VR_MIN
+ @IntDef(prefix = { "TEMPERATURE_" }, value = {
+ TEMPERATURE_CURRENT,
+ TEMPERATURE_THROTTLING,
+ TEMPERATURE_SHUTDOWN,
+ TEMPERATURE_THROTTLING_BELOW_VR_MIN
})
public @interface TemperatureSource {}
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/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 624e28a..96e7a59 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -871,7 +871,11 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag=true, value={EVENT_INPUT, EVENT_OUTPUT, EVENT_ERROR})
+ @IntDef(flag = true, prefix = { "EVENT_" }, value = {
+ EVENT_INPUT,
+ EVENT_OUTPUT,
+ EVENT_ERROR
+ })
public @interface Events {}
/**
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 068f5f7..56c6391 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -466,7 +466,7 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
+ @IntDef(prefix = { "SHUTDOWN_REASON_" }, value = {
SHUTDOWN_REASON_UNKNOWN,
SHUTDOWN_REASON_SHUTDOWN,
SHUTDOWN_REASON_REBOOT,
@@ -680,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.
@@ -1509,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/UserManager.java b/core/java/android/os/UserManager.java
index 22967af..fb60bbb 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -103,8 +103,12 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag=true, value={RESTRICTION_NOT_SET, RESTRICTION_SOURCE_SYSTEM,
- RESTRICTION_SOURCE_DEVICE_OWNER, RESTRICTION_SOURCE_PROFILE_OWNER})
+ @IntDef(flag = true, prefix = { "RESTRICTION_" }, value = {
+ RESTRICTION_NOT_SET,
+ RESTRICTION_SOURCE_SYSTEM,
+ RESTRICTION_SOURCE_DEVICE_OWNER,
+ RESTRICTION_SOURCE_PROFILE_OWNER
+ })
@SystemApi
public @interface UserRestrictionSource {}
@@ -2115,7 +2119,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 +2146,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/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index 9369eeb..6c9f1b2 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -130,7 +130,8 @@
* <p>Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when
* createAndManageUser is called by the device owner.
*/
- public abstract UserInfo createUserEvenWhenDisallowed(String name, int flags);
+ public abstract UserInfo createUserEvenWhenDisallowed(String name, int flags,
+ String[] disallowedPackages);
/**
* Same as {@link UserManager#removeUser(int userHandle)}, but bypasses the check for
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/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 4796712..9833fe1 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1690,7 +1690,7 @@
public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2;
/** @hide */
- @IntDef(flag = true, value = {
+ @IntDef(flag = true, prefix = { "FLAG_ALLOCATE_" }, value = {
FLAG_ALLOCATE_AGGRESSIVE,
FLAG_ALLOCATE_DEFY_ALL_RESERVED,
FLAG_ALLOCATE_DEFY_HALF_RESERVED,
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index ce5b11e..f0d9a0c 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -49,8 +49,9 @@
public final class PrintAttributes implements Parcelable {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {
- COLOR_MODE_MONOCHROME, COLOR_MODE_COLOR
+ @IntDef(flag = true, prefix = { "COLOR_MODE_" }, value = {
+ COLOR_MODE_MONOCHROME,
+ COLOR_MODE_COLOR
})
@interface ColorMode {
}
@@ -64,8 +65,10 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {
- DUPLEX_MODE_NONE, DUPLEX_MODE_LONG_EDGE, DUPLEX_MODE_SHORT_EDGE
+ @IntDef(flag = true, prefix = { "DUPLEX_MODE_" }, value = {
+ DUPLEX_MODE_NONE,
+ DUPLEX_MODE_LONG_EDGE,
+ DUPLEX_MODE_SHORT_EDGE
})
@interface DuplexMode {
}
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index 6143404..55c902e 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -83,11 +83,14 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
- CONTENT_TYPE_UNKNOWN, CONTENT_TYPE_DOCUMENT, CONTENT_TYPE_PHOTO
+ @IntDef(prefix = { "CONTENT_TYPE_" }, value = {
+ CONTENT_TYPE_UNKNOWN,
+ CONTENT_TYPE_DOCUMENT,
+ CONTENT_TYPE_PHOTO
})
public @interface ContentType {
}
+
/**
* Content type: unknown.
*/
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index 94686a8..85fdd64 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -45,9 +45,14 @@
public final class PrintJobInfo implements Parcelable {
/** @hide */
- @IntDef({
- STATE_CREATED, STATE_QUEUED, STATE_STARTED, STATE_BLOCKED, STATE_COMPLETED,
- STATE_FAILED, STATE_CANCELED
+ @IntDef(prefix = { "STATE_" }, value = {
+ STATE_CREATED,
+ STATE_QUEUED,
+ STATE_STARTED,
+ STATE_BLOCKED,
+ STATE_COMPLETED,
+ STATE_FAILED,
+ STATE_CANCELED
})
@Retention(RetentionPolicy.SOURCE)
public @interface State {
diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java
index 88feab7..e79cc65 100644
--- a/core/java/android/print/PrinterInfo.java
+++ b/core/java/android/print/PrinterInfo.java
@@ -53,12 +53,15 @@
public final class PrinterInfo implements Parcelable {
/** @hide */
- @IntDef({
- STATUS_IDLE, STATUS_BUSY, STATUS_UNAVAILABLE
+ @IntDef(prefix = { "STATUS_" }, value = {
+ STATUS_IDLE,
+ STATUS_BUSY,
+ STATUS_UNAVAILABLE
})
@Retention(RetentionPolicy.SOURCE)
public @interface Status {
}
+
/** Printer status: the printer is idle and ready to print. */
public static final int STATUS_IDLE = PrinterInfoProto.STATUS_IDLE;
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/FontsContract.java b/core/java/android/provider/FontsContract.java
index d8540ff..a1d1c57 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -283,7 +283,11 @@
public static final int STATUS_REJECTED = 3;
/** @hide */
- @IntDef({STATUS_OK, STATUS_WRONG_CERTIFICATES, STATUS_UNEXPECTED_DATA_PROVIDED})
+ @IntDef(prefix = { "STATUS_" }, value = {
+ STATUS_OK,
+ STATUS_WRONG_CERTIFICATES,
+ STATUS_UNEXPECTED_DATA_PROVIDED
+ })
@Retention(RetentionPolicy.SOURCE)
@interface FontResultStatus {}
@@ -438,9 +442,13 @@
public static final int FAIL_REASON_MALFORMED_QUERY = Columns.RESULT_CODE_MALFORMED_QUERY;
/** @hide */
- @IntDef({ FAIL_REASON_PROVIDER_NOT_FOUND, FAIL_REASON_FONT_LOAD_ERROR,
- FAIL_REASON_FONT_NOT_FOUND, FAIL_REASON_FONT_UNAVAILABLE,
- FAIL_REASON_MALFORMED_QUERY })
+ @IntDef(prefix = { "FAIL_" }, value = {
+ FAIL_REASON_PROVIDER_NOT_FOUND,
+ FAIL_REASON_FONT_LOAD_ERROR,
+ FAIL_REASON_FONT_NOT_FOUND,
+ FAIL_REASON_FONT_UNAVAILABLE,
+ FAIL_REASON_MALFORMED_QUERY
+ })
@Retention(RetentionPolicy.SOURCE)
@interface FontRequestFailReason {}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 729c0ff..4ecbdf5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1689,7 +1689,7 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
+ @IntDef(prefix = { "RESET_MODE_" }, value = {
RESET_MODE_PACKAGE_DEFAULTS,
RESET_MODE_UNTRUSTED_DEFAULTS,
RESET_MODE_UNTRUSTED_CHANGES,
@@ -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)
@@ -9524,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)
@@ -10117,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.
*
@@ -10430,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
*
@@ -10456,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.
*
@@ -10492,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 */
@@ -11066,7 +11134,7 @@
*
* <pre>
* default (int)
- * options_array (string)
+ * options_array (int[])
* </pre>
*
* All delays in integer minutes. Array order is respected.
@@ -11075,6 +11143,15 @@
*/
public static final String NOTIFICATION_SNOOZE_OPTIONS =
"notification_snooze_options";
+
+ /**
+ * Enable GNSS Raw Measurements Full Tracking?
+ * 0 = no
+ * 1 = yes
+ * @hide
+ */
+ public static final String ENABLE_GNSS_RAW_MEAS_FULL_TRACKING =
+ "enable_gnss_raw_meas_full_tracking";
}
/**
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 cd362c7..97fdcef 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -440,19 +440,25 @@
* 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
+ * {@link android.app.assist.AssistStructure.ViewNode view nodes} passed to this call, 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..a527f16 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);
}
}
}
@@ -235,12 +226,13 @@
public static final int TYPE_CONTEXT_COMMITTED = 4;
/** @hide */
- @IntDef(
- value = {TYPE_DATASET_SELECTED,
- TYPE_DATASET_AUTHENTICATION_SELECTED,
- TYPE_AUTHENTICATION_SELECTED,
- TYPE_SAVE_SHOWN,
- TYPE_CONTEXT_COMMITTED})
+ @IntDef(prefix = { "TYPE_" }, value = {
+ TYPE_DATASET_SELECTED,
+ TYPE_DATASET_AUTHENTICATION_SELECTED,
+ TYPE_AUTHENTICATION_SELECTED,
+ TYPE_SAVE_SHOWN,
+ TYPE_CONTEXT_COMMITTED
+ })
@Retention(RetentionPolicy.SOURCE)
@interface EventIds{}
@@ -259,8 +251,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 +356,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 +469,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 +477,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 +500,9 @@
}
mManuallyFilledFieldIds = manuallyFilledFieldIds;
mManuallyFilledDatasetIds = manuallyFilledDatasetIds;
- mDetectedRemoteId = detectedRemoteId;
- mDetectedFieldScore = detectedFieldScore;
+
+ mDetectedFieldIds = detectedFieldIds;
+ mDetectedMatches = detectedMaches;
}
@Override
@@ -524,8 +515,8 @@
+ ", changedDatasetsIds=" + mChangedDatasetIds
+ ", manuallyFilledFieldIds=" + mManuallyFilledFieldIds
+ ", manuallyFilledDatasetIds=" + mManuallyFilledDatasetIds
- + ", detectedRemoteId=" + mDetectedRemoteId
- + ", detectedFieldScore=" + mDetectedFieldScore
+ + ", detectedFieldIds=" + Arrays.toString(mDetectedFieldIds)
+ + ", detectedMaches =" + Arrays.toString(mDetectedMatches)
+ "]";
}
}
@@ -534,7 +525,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 +552,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/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 3a84224..33619ac 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -69,9 +69,9 @@
public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
/** @hide */
- @IntDef(
- flag = true,
- value = {FLAG_MANUAL_REQUEST})
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+ FLAG_MANUAL_REQUEST
+ })
@Retention(RetentionPolicy.SOURCE)
@interface RequestFlags{}
@@ -127,12 +127,15 @@
}
/**
- * Gets the extra client state returned from the last {@link
- * AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)
- * fill request}, so the service can use it for state management.
+ * Gets the latest client state bundle set by the service in a
+ * {@link FillResponse.Builder#setClientState(Bundle) fill response}.
*
- * <p>Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)
- * save request} is made, the client state is cleared.
+ * <p><b>Note:</b> Prior to Android {@link android.os.Build.VERSION_CODES#P}, only client state
+ * bundles set by {@link FillResponse.Builder#setClientState(Bundle)} were considered. On
+ * Android {@link android.os.Build.VERSION_CODES#P} and higher, bundles set in the result of
+ * an authenticated request through the
+ * {@link android.view.autofill.AutofillManager#EXTRA_CLIENT_STATE} extra are
+ * also considered (and take precedence when set).
*
* @return The client state.
*/
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 84a0974..014d3e8 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -49,19 +49,21 @@
public final class FillResponse implements Parcelable {
/**
- * Must be set in the last response to generate
- * {@link FillEventHistory.Event#TYPE_CONTEXT_COMMITTED} events.
+ * Flag used to generate {@link FillEventHistory.Event events} of type
+ * {@link FillEventHistory.Event#TYPE_CONTEXT_COMMITTED}—if this flag is not passed to
+ * {@link Builder#setFlags(int)}, these events are not generated.
*/
public static final int FLAG_TRACK_CONTEXT_COMMITED = 0x1;
/**
- * Used in conjunction to {@link FillResponse.Builder#disableAutofill(long)} to disable autofill
- * only for the activiy associated with the {@link FillResponse}, instead of the whole app.
+ * Flag used to change the behavior of {@link FillResponse.Builder#disableAutofill(long)}—
+ * when this flag is passed to {@link Builder#setFlags(int)}, autofill is disabled only for the
+ * activiy that generated the {@link FillRequest}, not the whole app.
*/
public static final int FLAG_DISABLE_ACTIVITY_ONLY = 0x2;
/** @hide */
- @IntDef(flag = true, value = {
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
FLAG_TRACK_CONTEXT_COMMITED,
FLAG_DISABLE_ACTIVITY_ONLY
})
@@ -72,11 +74,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 +89,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 +121,16 @@
}
/** @hide */
+ public @Nullable RemoteViews getHeader() {
+ return mHeader;
+ }
+
+ /** @hide */
+ public @Nullable RemoteViews getFooter() {
+ return mFooter;
+ }
+
+ /** @hide */
public @Nullable IntentSender getAuthentication() {
return mAuthentication;
}
@@ -135,8 +151,8 @@
}
/** @hide */
- public @Nullable FieldsDetection getFieldsDetection() {
- return mFieldsDetection;
+ public @Nullable AutofillId[] getFieldClassificationIds() {
+ return mFieldClassificationIds;
}
/** @hide */
@@ -171,11 +187,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 +244,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");
}
@@ -305,19 +331,16 @@
}
/**
- * Sets a {@link Bundle state} that will be passed to subsequent APIs that
- * manipulate this response. For example, they are passed to subsequent
- * calls to {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal,
- * FillCallback)} and {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)}.
- * You can use this to store intermediate state that is persistent across multiple
- * fill requests and the subsequent save request.
+ * Sets a bundle with state that is passed to subsequent APIs that manipulate this response.
+ *
+ * <p>You can use this bundle to store intermediate state that is passed to subsequent calls
+ * to {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal,
+ * FillCallback)} and {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)}, and
+ * you can also retrieve it by calling {@link FillEventHistory.Event#getClientState()}.
*
* <p>If this method is called on multiple {@link FillResponse} objects for the same
* screen, just the latest bundle is passed back to the service.
*
- * <p>Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)
- * save request} is made the client state is cleared.
- *
* @param clientState The custom client state.
* @return This builder.
*/
@@ -329,21 +352,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 +422,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 +441,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 +505,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 +542,12 @@
throw new IllegalStateException("Already called #disableAutofill()");
}
}
+
+ private void throwIfAuthenticationCalled() {
+ if (mAuthentication != null) {
+ throw new IllegalStateException("Already called #setAuthentication()");
+ }
+ }
}
/////////////////////////////////////
@@ -461,12 +564,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 +594,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 +628,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/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 0b50f07..a5a6177 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -198,23 +198,22 @@
public static final int NEGATIVE_BUTTON_STYLE_REJECT = 1;
/** @hide */
- @IntDef(
- value = {
- NEGATIVE_BUTTON_STYLE_CANCEL,
- NEGATIVE_BUTTON_STYLE_REJECT})
+ @IntDef(prefix = { "NEGATIVE_BUTTON_STYLE_" }, value = {
+ NEGATIVE_BUTTON_STYLE_CANCEL,
+ NEGATIVE_BUTTON_STYLE_REJECT
+ })
@Retention(RetentionPolicy.SOURCE)
@interface NegativeButtonStyle{}
/** @hide */
- @IntDef(
- flag = true,
- value = {
- SAVE_DATA_TYPE_GENERIC,
- SAVE_DATA_TYPE_PASSWORD,
- SAVE_DATA_TYPE_ADDRESS,
- SAVE_DATA_TYPE_CREDIT_CARD,
- SAVE_DATA_TYPE_USERNAME,
- SAVE_DATA_TYPE_EMAIL_ADDRESS})
+ @IntDef(flag = true, prefix = { "SAVE_DATA_TYPE_" }, value = {
+ SAVE_DATA_TYPE_GENERIC,
+ SAVE_DATA_TYPE_PASSWORD,
+ SAVE_DATA_TYPE_ADDRESS,
+ SAVE_DATA_TYPE_CREDIT_CARD,
+ SAVE_DATA_TYPE_USERNAME,
+ SAVE_DATA_TYPE_EMAIL_ADDRESS
+ })
@Retention(RetentionPolicy.SOURCE)
@interface SaveDataType{}
@@ -235,9 +234,10 @@
public static final int FLAG_DONT_SAVE_ON_FINISH = 0x2;
/** @hide */
- @IntDef(
- flag = true,
- value = {FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE, FLAG_DONT_SAVE_ON_FINISH})
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+ FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE,
+ FLAG_DONT_SAVE_ON_FINISH
+ })
@Retention(RetentionPolicy.SOURCE)
@interface SaveInfoFlags{}
diff --git a/core/java/android/service/autofill/SaveRequest.java b/core/java/android/service/autofill/SaveRequest.java
index f53967b..4f85e6b 100644
--- a/core/java/android/service/autofill/SaveRequest.java
+++ b/core/java/android/service/autofill/SaveRequest.java
@@ -59,10 +59,11 @@
}
/**
- * Gets the latest client state extra returned from the service.
+ * Gets the latest client state bundle set by the service in a
+ * {@link FillResponse.Builder#setClientState(Bundle) fill response}.
*
* <p><b>Note:</b> Prior to Android {@link android.os.Build.VERSION_CODES#P}, only client state
- * bundles set by {@link FillResponse.Builder#setClientState(Bundle)} where considered. On
+ * bundles set by {@link FillResponse.Builder#setClientState(Bundle)} were considered. On
* Android {@link android.os.Build.VERSION_CODES#P} and higher, bundles set in the result of
* an authenticated request through the
* {@link android.view.autofill.AutofillManager#EXTRA_CLIENT_STATE} extra are
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 1c83868..0f1ba98 100644
--- a/core/java/android/service/autofill/Validators.java
+++ b/core/java/android/service/autofill/Validators.java
@@ -33,6 +33,8 @@
/**
* Creates a validator that is only valid if all {@code validators} are valid.
*
+ * <p>Used to represent an {@code AND} boolean operation in a chain of validators.
+ *
* @throws IllegalArgumentException if any element of {@code validators} is an instance of a
* class that is not provided by the Android System.
*/
@@ -44,6 +46,8 @@
/**
* Creates a validator that is valid if any of the {@code validators} is valid.
*
+ * <p>Used to represent an {@code OR} boolean operation in a chain of validators.
+ *
* @throws IllegalArgumentException if any element of {@code validators} is an instance of a
* class that is not provided by the Android System.
*/
@@ -53,7 +57,9 @@
}
/**
- * Creates a validator that is valid only if {@code validator} is not.
+ * Creates a validator that is valid when {@code validator} is not, and vice versa.
+ *
+ * <p>Used to represent a {@code NOT} boolean operation in a chain of validators.
*
* @throws IllegalArgumentException if {@code validator} is an instance of a class that is not
* provided by the Android System.
diff --git a/core/java/android/service/dreams/OWNERS b/core/java/android/service/dreams/OWNERS
new file mode 100644
index 0000000..3c9bbf8
--- /dev/null
+++ b/core/java/android/service/dreams/OWNERS
@@ -0,0 +1,3 @@
+dsandler@google.com
+michaelwr@google.com
+roosa@google.com
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/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index 447afe6..2a352ad 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -39,7 +39,12 @@
public static final String SCHEME = "condition";
/** @hide */
- @IntDef({STATE_FALSE, STATE_TRUE, STATE_TRUE, STATE_ERROR})
+ @IntDef(prefix = { "STATE_" }, value = {
+ STATE_FALSE,
+ STATE_TRUE,
+ STATE_UNKNOWN,
+ STATE_ERROR
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface State {}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index dac663e7..18d4a1e 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -229,8 +229,11 @@
/** @hide */
- @IntDef({NOTIFICATION_CHANNEL_OR_GROUP_ADDED, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED,
- NOTIFICATION_CHANNEL_OR_GROUP_DELETED})
+ @IntDef(prefix = { "NOTIFICATION_CHANNEL_OR_GROUP_" }, value = {
+ NOTIFICATION_CHANNEL_OR_GROUP_ADDED,
+ NOTIFICATION_CHANNEL_OR_GROUP_UPDATED,
+ NOTIFICATION_CHANNEL_OR_GROUP_DELETED
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface ChannelOrGroupModificationTypes {}
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/persistentdata/PersistentDataBlockManager.java b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
index 9332a5b..0bf68b7 100644
--- a/core/java/android/service/persistentdata/PersistentDataBlockManager.java
+++ b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
@@ -65,10 +65,10 @@
*/
public static final int FLASH_LOCK_LOCKED = 1;
- @IntDef({
- FLASH_LOCK_UNKNOWN,
- FLASH_LOCK_LOCKED,
- FLASH_LOCK_UNLOCKED,
+ @IntDef(prefix = { "FLASH_LOCK_" }, value = {
+ FLASH_LOCK_UNKNOWN,
+ FLASH_LOCK_LOCKED,
+ FLASH_LOCK_UNLOCKED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface FlashLockState {}
diff --git a/core/java/android/service/settings/suggestions/Suggestion.java b/core/java/android/service/settings/suggestions/Suggestion.java
index cfeb7fc..11e1e67 100644
--- a/core/java/android/service/settings/suggestions/Suggestion.java
+++ b/core/java/android/service/settings/suggestions/Suggestion.java
@@ -38,7 +38,7 @@
/**
* @hide
*/
- @IntDef(flag = true, value = {
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
FLAG_HAS_BUTTON,
})
@Retention(RetentionPolicy.SOURCE)
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 5ef934e..4bade9f 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -114,11 +114,10 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- value = {
- FLAG_GRANT_TRUST_INITIATED_BY_USER,
- FLAG_GRANT_TRUST_DISMISS_KEYGUARD,
- })
+ @IntDef(flag = true, prefix = { "FLAG_GRANT_TRUST_" }, value = {
+ FLAG_GRANT_TRUST_INITIATED_BY_USER,
+ FLAG_GRANT_TRUST_DISMISS_KEYGUARD,
+ })
public @interface GrantTrustFlags {}
@@ -138,11 +137,10 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- value = {
- TOKEN_STATE_ACTIVE,
- TOKEN_STATE_INACTIVE,
- })
+ @IntDef(flag = true, prefix = { "TOKEN_STATE_" }, value = {
+ TOKEN_STATE_ACTIVE,
+ TOKEN_STATE_INACTIVE,
+ })
public @interface TokenState {}
private static final int MSG_UNLOCK_ATTEMPT = 1;
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 9464a87..76d89ef 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -87,11 +87,11 @@
// Keyphrase management actions. Used in getManageIntent() ----//
@Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- MANAGE_ACTION_ENROLL,
- MANAGE_ACTION_RE_ENROLL,
- MANAGE_ACTION_UN_ENROLL
- })
+ @IntDef(prefix = { "MANAGE_ACTION_" }, value = {
+ MANAGE_ACTION_ENROLL,
+ MANAGE_ACTION_RE_ENROLL,
+ MANAGE_ACTION_UN_ENROLL
+ })
private @interface ManageActions {}
/**
@@ -116,12 +116,11 @@
//-- Flags for startRecognition ----//
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- value = {
- RECOGNITION_FLAG_NONE,
- RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO,
- RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS
- })
+ @IntDef(flag = true, prefix = { "RECOGNITION_FLAG_" }, value = {
+ RECOGNITION_FLAG_NONE,
+ RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO,
+ RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS
+ })
public @interface RecognitionFlags {}
/**
@@ -150,11 +149,10 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- value = {
- RECOGNITION_MODE_VOICE_TRIGGER,
- RECOGNITION_MODE_USER_IDENTIFICATION,
- })
+ @IntDef(flag = true, prefix = { "RECOGNITION_MODE_" }, value = {
+ RECOGNITION_MODE_VOICE_TRIGGER,
+ RECOGNITION_MODE_USER_IDENTIFICATION,
+ })
public @interface RecognitionModes {}
/**
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 dd0ae33..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,12 +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,
- null /* displayCutout */);
+ mDispatchedDisplayCutout);
if (DEBUG) {
Log.v(TAG, "dispatching insets=" + insets);
}
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 763ea2c..01562b3 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -80,8 +80,15 @@
public static final int STOPPED = -2;
/** @hide */
- @IntDef({ERROR_SYNTHESIS, ERROR_SERVICE, ERROR_OUTPUT, ERROR_NETWORK, ERROR_NETWORK_TIMEOUT,
- ERROR_INVALID_REQUEST, ERROR_NOT_INSTALLED_YET})
+ @IntDef(prefix = { "ERROR_" }, value = {
+ ERROR_SYNTHESIS,
+ ERROR_SERVICE,
+ ERROR_OUTPUT,
+ ERROR_NETWORK,
+ ERROR_NETWORK_TIMEOUT,
+ ERROR_INVALID_REQUEST,
+ ERROR_NOT_INSTALLED_YET
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Error {}
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/FontConfig.java b/core/java/android/text/FontConfig.java
index 4654e83..7386e3e 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -179,7 +179,11 @@
/** @hide */
@Retention(SOURCE)
- @IntDef({VARIANT_DEFAULT, VARIANT_COMPACT, VARIANT_ELEGANT})
+ @IntDef(prefix = { "VARIANT_" }, value = {
+ VARIANT_DEFAULT,
+ VARIANT_COMPACT,
+ VARIANT_ELEGANT
+ })
public @interface Variant {}
/**
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 4d2a962..bf4b6ac 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -48,7 +48,11 @@
*/
public abstract class Layout {
/** @hide */
- @IntDef({BREAK_STRATEGY_SIMPLE, BREAK_STRATEGY_HIGH_QUALITY, BREAK_STRATEGY_BALANCED})
+ @IntDef(prefix = { "BREAK_STRATEGY_" }, value = {
+ BREAK_STRATEGY_SIMPLE,
+ BREAK_STRATEGY_HIGH_QUALITY,
+ BREAK_STRATEGY_BALANCED
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface BreakStrategy {}
@@ -73,8 +77,11 @@
public static final int BREAK_STRATEGY_BALANCED = 2;
/** @hide */
- @IntDef({HYPHENATION_FREQUENCY_NORMAL, HYPHENATION_FREQUENCY_FULL,
- HYPHENATION_FREQUENCY_NONE})
+ @IntDef(prefix = { "HYPHENATION_FREQUENCY_" }, value = {
+ HYPHENATION_FREQUENCY_NORMAL,
+ HYPHENATION_FREQUENCY_FULL,
+ HYPHENATION_FREQUENCY_NONE
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface HyphenationFrequency {}
@@ -105,7 +112,10 @@
ArrayUtils.emptyArray(ParagraphStyle.class);
/** @hide */
- @IntDef({JUSTIFICATION_MODE_NONE, JUSTIFICATION_MODE_INTER_WORD})
+ @IntDef(prefix = { "JUSTIFICATION_MODE_" }, value = {
+ JUSTIFICATION_MODE_NONE,
+ JUSTIFICATION_MODE_INTER_WORD
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface JustificationMode {}
@@ -1907,22 +1917,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 +1957,9 @@
return margin + Math.abs(tl.metrics(null));
} finally {
TextLine.recycle(tl);
- MeasuredText.recycle(mt);
+ if (mt != null) {
+ mt.recycle();
+ }
}
}
@@ -2272,6 +2276,14 @@
private SpanSet<LineBackgroundSpan> mLineBackgroundSpans;
private int mJustificationMode;
+ /** @hide */
+ @IntDef(prefix = { "DIR_" }, value = {
+ 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;
@@ -2309,7 +2321,10 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({TEXT_SELECTION_LAYOUT_RIGHT_TO_LEFT, TEXT_SELECTION_LAYOUT_LEFT_TO_RIGHT})
+ @IntDef(prefix = { "TEXT_SELECTION_LAYOUT_" }, value = {
+ TEXT_SELECTION_LAYOUT_RIGHT_TO_LEFT,
+ TEXT_SELECTION_LAYOUT_LEFT_TO_RIGHT
+ })
public @interface TextSelectionLayout {}
/** @hide */
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/PremeasuredText.java b/core/java/android/text/PremeasuredText.java
new file mode 100644
index 0000000..465314d
--- /dev/null
+++ b/core/java/android/text/PremeasuredText.java
@@ -0,0 +1,272 @@
+/*
+ * 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 android.util.IntArray;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+
+/**
+ * A text which has already been measured.
+ *
+ * TODO: Rename to better name? e.g. MeasuredText, FrozenText etc.
+ */
+public class PremeasuredText implements Spanned {
+ private static final char LINE_FEED = '\n';
+
+ // The original text.
+ private final @NonNull CharSequence mText;
+
+ // The inclusive start offset of the measuring target.
+ private final @IntRange(from = 0) int mStart;
+
+ // The exclusive end offset of the measuring target.
+ private final @IntRange(from = 0) int mEnd;
+
+ // The TextPaint used for measurement.
+ private final @NonNull TextPaint mPaint;
+
+ // The requested text direction.
+ private final @NonNull TextDirectionHeuristic mTextDir;
+
+ // The measured paragraph texts.
+ private final @NonNull MeasuredText[] mMeasuredTexts;
+
+ // The sorted paragraph end offsets.
+ private final @NonNull int[] mParagraphBreakPoints;
+
+ /**
+ * Build PremeasuredText from the text.
+ *
+ * @param text The text to be measured.
+ * @param paint The paint to be used for drawing.
+ * @param textDir The text direction.
+ * @return The measured text.
+ */
+ public static @NonNull PremeasuredText build(@NonNull CharSequence text,
+ @NonNull TextPaint paint,
+ @NonNull TextDirectionHeuristic textDir) {
+ return PremeasuredText.build(text, paint, textDir, 0, text.length());
+ }
+
+ /**
+ * Build PremeasuredText from the specific range of the text..
+ *
+ * @param text The text to be measured.
+ * @param paint The paint to be used for drawing.
+ * @param textDir The text direction.
+ * @param start The inclusive start offset of the text.
+ * @param end The exclusive start offset of the text.
+ * @return The measured text.
+ */
+ public static @NonNull PremeasuredText build(@NonNull CharSequence text,
+ @NonNull TextPaint paint,
+ @NonNull TextDirectionHeuristic textDir,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end) {
+ Preconditions.checkNotNull(text);
+ Preconditions.checkNotNull(paint);
+ Preconditions.checkNotNull(textDir);
+ Preconditions.checkArgumentInRange(start, 0, text.length(), "start");
+ Preconditions.checkArgumentInRange(end, 0, text.length(), "end");
+
+ final IntArray paragraphEnds = new IntArray();
+ final ArrayList<MeasuredText> measuredTexts = new ArrayList<>();
+
+ int paraEnd = 0;
+ for (int paraStart = start; paraStart < end; paraStart = paraEnd) {
+ paraEnd = TextUtils.indexOf(text, LINE_FEED, paraStart, end);
+ if (paraEnd < 0) {
+ // No LINE_FEED(U+000A) character found. Use end of the text as the paragraph end.
+ paraEnd = end;
+ } else {
+ paraEnd++; // Includes LINE_FEED(U+000A) to the prev paragraph.
+ }
+
+ paragraphEnds.add(paraEnd);
+ measuredTexts.add(MeasuredText.buildForStaticLayout(
+ paint, text, paraStart, paraEnd, textDir, null /* no recycle */));
+ }
+
+ return new PremeasuredText(text, start, end, paint, textDir,
+ measuredTexts.toArray(new MeasuredText[measuredTexts.size()]),
+ paragraphEnds.toArray());
+ }
+
+ // Use PremeasuredText.build instead.
+ private PremeasuredText(@NonNull CharSequence text,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end,
+ @NonNull TextPaint paint,
+ @NonNull TextDirectionHeuristic textDir,
+ @NonNull MeasuredText[] measuredTexts,
+ @NonNull int[] paragraphBreakPoints) {
+ mText = text;
+ mStart = start;
+ mEnd = end;
+ mPaint = paint;
+ mMeasuredTexts = measuredTexts;
+ mParagraphBreakPoints = paragraphBreakPoints;
+ mTextDir = textDir;
+ }
+
+ /**
+ * Return the underlying text.
+ */
+ public @NonNull CharSequence getText() {
+ return mText;
+ }
+
+ /**
+ * Returns the inclusive start offset of measured region.
+ */
+ public @IntRange(from = 0) int getStart() {
+ return mStart;
+ }
+
+ /**
+ * Returns the exclusive end offset of measured region.
+ */
+ public @IntRange(from = 0) int getEnd() {
+ return mEnd;
+ }
+
+ /**
+ * Returns the text direction associated with char sequence.
+ */
+ public @NonNull TextDirectionHeuristic getTextDir() {
+ return mTextDir;
+ }
+
+ /**
+ * Returns the paint used to measure this text.
+ */
+ public @NonNull TextPaint getPaint() {
+ return mPaint;
+ }
+
+ /**
+ * Returns the length of the paragraph of this text.
+ */
+ public @IntRange(from = 0) int getParagraphCount() {
+ return mParagraphBreakPoints.length;
+ }
+
+ /**
+ * Returns the paragraph start offset of the text.
+ */
+ public @IntRange(from = 0) int getParagraphStart(@IntRange(from = 0) int paraIndex) {
+ Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex");
+ return paraIndex == 0 ? mStart : mParagraphBreakPoints[paraIndex - 1];
+ }
+
+ /**
+ * Returns the paragraph end offset of the text.
+ */
+ public @IntRange(from = 0) int getParagraphEnd(@IntRange(from = 0) int paraIndex) {
+ Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex");
+ return mParagraphBreakPoints[paraIndex];
+ }
+
+ /** @hide */
+ public @NonNull MeasuredText getMeasuredText(@IntRange(from = 0) int paraIndex) {
+ return mMeasuredTexts[paraIndex];
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // Spanned overrides
+ //
+ // Just proxy for underlying mText if appropriate.
+
+ @Override
+ public <T> T[] getSpans(int start, int end, Class<T> type) {
+ if (mText instanceof Spanned) {
+ return ((Spanned) mText).getSpans(start, end, type);
+ } else {
+ return ArrayUtils.emptyArray(type);
+ }
+ }
+
+ @Override
+ public int getSpanStart(Object tag) {
+ if (mText instanceof Spanned) {
+ return ((Spanned) mText).getSpanStart(tag);
+ } else {
+ return -1;
+ }
+ }
+
+ @Override
+ public int getSpanEnd(Object tag) {
+ if (mText instanceof Spanned) {
+ return ((Spanned) mText).getSpanEnd(tag);
+ } else {
+ return -1;
+ }
+ }
+
+ @Override
+ public int getSpanFlags(Object tag) {
+ if (mText instanceof Spanned) {
+ return ((Spanned) mText).getSpanFlags(tag);
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public int nextSpanTransition(int start, int limit, Class type) {
+ if (mText instanceof Spanned) {
+ return ((Spanned) mText).nextSpanTransition(start, limit, type);
+ } else {
+ return mText.length();
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // CharSequence overrides.
+ //
+ // Just proxy for underlying mText.
+
+ @Override
+ public int length() {
+ return mText.length();
+ }
+
+ @Override
+ public char charAt(int index) {
+ // TODO: Should this be index + mStart ?
+ return mText.charAt(index);
+ }
+
+ @Override
+ public CharSequence subSequence(int start, int end) {
+ // TODO: return PremeasuredText.
+ // TODO: Should this be index + mStart, end + mStart ?
+ return mText.subSequence(start, end);
+ }
+
+ @Override
+ public String toString() {
+ return mText.toString();
+ }
+}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index c0fc44f..2e10fe8 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);
}
@@ -606,8 +610,8 @@
/* package */ void generate(Builder b, boolean includepad, boolean trackpad) {
final CharSequence source = b.mText;
- int bufStart = b.mStart;
- int bufEnd = b.mEnd;
+ final int bufStart = b.mStart;
+ final int bufEnd = b.mEnd;
TextPaint paint = b.mPaint;
int outerWidth = b.mWidth;
TextDirectionHeuristic textDir = b.mTextDir;
@@ -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,12 +634,6 @@
Paint.FontMetricsInt fm = b.mFontMetricsInt;
int[] chooseHtv = null;
- MeasuredText measured = b.mMeasuredText;
-
- Spanned spanned = null;
- if (source instanceof Spanned)
- spanned = (Spanned) source;
-
final int[] indents;
if (mLeftIndents != null || mRightIndents != null) {
final int leftLen = mLeftIndents == null ? 0 : mLeftIndents.length;
@@ -662,15 +656,34 @@
b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE,
indents, mLeftPaddings, mRightPaddings);
+ PremeasuredText premeasured = null;
+ final Spanned spanned;
+ if (source instanceof PremeasuredText) {
+ premeasured = (PremeasuredText) source;
+
+ final CharSequence original = premeasured.getText();
+ spanned = (original instanceof Spanned) ? (Spanned) original : null;
+
+ if (bufStart != premeasured.getStart() || bufEnd != premeasured.getEnd()) {
+ // The buffer position has changed. Re-measure here.
+ premeasured = PremeasuredText.build(original, paint, textDir, bufStart, bufEnd);
+ } else {
+ // We can use premeasured information.
+
+ // Overwrite with the one when premeasured.
+ // TODO: Give an option for developer not to overwrite and measure again here?
+ textDir = premeasured.getTextDir();
+ paint = premeasured.getPaint();
+ }
+ } else {
+ premeasured = PremeasuredText.build(source, paint, textDir, bufStart, bufEnd);
+ spanned = (source instanceof Spanned) ? (Spanned) source : null;
+ }
+
try {
- int paraEnd;
- for (int paraStart = bufStart; paraStart <= bufEnd; paraStart = paraEnd) {
- paraEnd = TextUtils.indexOf(source, CHAR_NEW_LINE, paraStart, bufEnd);
- if (paraEnd < 0) {
- paraEnd = bufEnd;
- } else {
- paraEnd++;
- }
+ for (int paraIndex = 0; paraIndex < premeasured.getParagraphCount(); paraIndex++) {
+ final int paraStart = premeasured.getParagraphStart(paraIndex);
+ final int paraEnd = premeasured.getParagraphEnd(paraIndex);
int firstWidthLineCount = 1;
int firstWidth = outerWidth;
@@ -721,13 +734,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 +749,23 @@
}
}
+ final MeasuredText measured = premeasured.getMeasuredText(paraIndex);
+ 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 +782,7 @@
lineBreaks.ascents,
lineBreaks.descents,
lineBreaks.flags,
- widths);
+ widths.getRawArray());
final int[] breaks = lineBreaks.breaks;
final float[] lineWidths = lineBreaks.widths;
@@ -832,7 +805,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 +869,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,17 +900,16 @@
if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE)
&& mLineCount < mMaximumVisibleLineCount) {
- measured.setPara(source, bufEnd, bufEnd, textDir);
-
+ final MeasuredText measured =
+ MeasuredText.buildForBidi(source, bufEnd, bufEnd, textDir, null);
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, measured, bufEnd,
includepad, trackpad, addLastLineSpacing, null,
null, bufStart, ellipsize,
ellipsizedWidth, 0, paint, false);
@@ -952,8 +924,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, @NonNull 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 +933,7 @@
final int off = j * mColumns;
final int want = off + mColumns + TOP;
int[] lines = mLines;
+ final int dir = measured.getParagraphDir();
if (want >= lines.length) {
final int[] grow = ArrayUtils.newUnpaddedIntArray(GrowingArrayUtils.growSize(want));
@@ -986,17 +959,8 @@
// 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;
- } 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);
final boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount);
@@ -1473,33 +1437,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 +1449,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 +1461,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/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 5b851ca..f0838a1 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -52,7 +52,10 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag=true, value={MODE_IN, MODE_OUT})
+ @IntDef(flag = true, prefix = { "MODE_" }, value = {
+ MODE_IN,
+ MODE_OUT
+ })
@interface VisibilityMode {}
/**
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 29baea1..54b48b6 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,18 @@
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");
+ DEFAULT_FLAGS.put("settings_battery_display_app_list", "false");
+ }
+
/**
* Whether or not a flag is enabled.
*
@@ -41,7 +54,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 +70,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 +86,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/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 1808123..a74a882 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -917,18 +917,6 @@
}
}
- public static class SignatureNotFoundException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public SignatureNotFoundException(String message) {
- super(message);
- }
-
- public SignatureNotFoundException(String message, Throwable cause) {
- super(message, cause);
- }
- }
-
/**
* {@link DataDigester} that updates multiple {@link MessageDigest}s whenever data is feeded.
*/
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
new file mode 100644
index 0000000..73a9478
--- /dev/null
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -0,0 +1,263 @@
+/*
+ * 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.apk;
+
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.Signature;
+import android.os.Trace;
+import android.util.jar.StrictJarFile;
+
+import com.android.internal.util.ArrayUtils;
+
+import libcore.io.IoUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.zip.ZipEntry;
+
+/**
+ * Facade class that takes care of the details of APK verification on
+ * behalf of PackageParser.
+ *
+ * @hide for internal use only.
+ */
+public class ApkSignatureVerifier {
+
+ public static final int VERSION_JAR_SIGNATURE_SCHEME = 1;
+ public static final int VERSION_APK_SIGNATURE_SCHEME_V2 = 2;
+
+ private static final AtomicReference<byte[]> sBuffer = new AtomicReference<>();
+
+ /**
+ * Verifies the provided APK and returns the certificates associated with each signer. Also
+ * ensures that the provided APK contains an AndroidManifest.xml file.
+ *
+ * @param systemDir systemDir apk contents are already trusted, so we don't need to enforce
+ * v2 stripping rollback protection, or verify integrity of the APK.
+ *
+ * @throws PackageParserException if the APK's signature failed to verify.
+ * @throws SignatureNotFoundException if a signature corresponding to minLevel or greater
+ * is not found, except in the case of no JAR signature.
+ */
+ public static Result verify(String apkPath, int minSignatureSchemeVersion, boolean systemDir)
+ throws PackageParserException, SignatureNotFoundException {
+ boolean verified = false;
+ Certificate[][] signerCerts;
+ int level = VERSION_APK_SIGNATURE_SCHEME_V2;
+
+ // first try v2
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV2");
+ try {
+ signerCerts = ApkSignatureSchemeV2Verifier.verify(apkPath);
+ Signature[] signerSigs = convertToSignatures(signerCerts);
+
+ // sanity check - must have an AndroidManifest file
+ StrictJarFile jarFile = null;
+ try {
+ jarFile = new StrictJarFile(apkPath, false, false);
+ final ZipEntry manifestEntry =
+ jarFile.findEntry(PackageParser.ANDROID_MANIFEST_FILENAME);
+ if (manifestEntry == null) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Package " + apkPath + " has no manifest");
+ }
+ } finally {
+ closeQuietly(jarFile);
+ }
+ return new Result(signerCerts, signerSigs);
+ } catch (SignatureNotFoundException e) {
+ // not signed with v2, try older if allowed
+ if (minSignatureSchemeVersion >= VERSION_APK_SIGNATURE_SCHEME_V2) {
+ throw new SignatureNotFoundException(
+ "No APK Signature Scheme v2 signature found for " + apkPath, e);
+ }
+ } catch (PackageParserException e) {
+ // preserve any new exceptions explicitly thrown here
+ throw e;
+ } catch (Exception e) {
+ // APK Signature Scheme v2 signature found but did not verify
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "Failed to collect certificates from " + apkPath
+ + " using APK Signature Scheme v2", e);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ // v2 didn't work, try jarsigner
+ return verifyV1Signature(apkPath, systemDir);
+ }
+
+ private static Result verifyV1Signature(String apkPath, boolean systemDir)
+ throws PackageParserException {
+ StrictJarFile jarFile = null;
+
+ try {
+ final Certificate[][] lastCerts;
+ final Signature[] lastSigs;
+
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
+ jarFile = new StrictJarFile(apkPath, true, !systemDir);
+ final List<ZipEntry> toVerify = new ArrayList<>();
+
+ // Always verify manifest, regardless of source
+ final ZipEntry manifestEntry = jarFile.findEntry(
+ PackageParser.ANDROID_MANIFEST_FILENAME);
+ if (manifestEntry == null) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Package " + apkPath + " has no manifest");
+ }
+ lastCerts = loadCertificates(jarFile, manifestEntry);
+ if (ArrayUtils.isEmpty(lastCerts)) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "Package "
+ + apkPath + " has no certificates at entry "
+ + PackageParser.ANDROID_MANIFEST_FILENAME);
+ }
+ lastSigs = convertToSignatures(lastCerts);
+
+ // don't waste time on already-trusted packages
+ if (!systemDir) {
+ final Iterator<ZipEntry> i = jarFile.iterator();
+ while (i.hasNext()) {
+ final ZipEntry entry = i.next();
+ if (entry.isDirectory()) continue;
+
+ final String entryName = entry.getName();
+ if (entryName.startsWith("META-INF/")) continue;
+ if (entryName.equals(PackageParser.ANDROID_MANIFEST_FILENAME)) continue;
+
+ toVerify.add(entry);
+ }
+
+ // Verify that entries are signed consistently with the first entry
+ // we encountered. Note that for splits, certificates may have
+ // already been populated during an earlier parse of a base APK.;
+ for (ZipEntry entry : toVerify) {
+ final Certificate[][] entryCerts = loadCertificates(jarFile, entry);
+ if (ArrayUtils.isEmpty(entryCerts)) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "Package " + apkPath + " has no certificates at entry "
+ + entry.getName());
+ }
+
+ // make sure all entries use the same signing certs
+ final Signature[] entrySigs = convertToSignatures(entryCerts);
+ if (!Signature.areExactMatch(lastSigs, entrySigs)) {
+ throw new PackageParserException(
+ INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+ "Package " + apkPath + " has mismatched certificates at entry "
+ + entry.getName());
+ }
+ }
+ }
+ return new Result(lastCerts, lastSigs);
+ } catch (GeneralSecurityException e) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
+ "Failed to collect certificates from " + apkPath, e);
+ } catch (IOException | RuntimeException e) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "Failed to collect certificates from " + apkPath, e);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ closeQuietly(jarFile);
+ }
+ }
+
+ private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry entry)
+ throws PackageParserException {
+ InputStream is = null;
+ try {
+ // We must read the stream for the JarEntry to retrieve
+ // its certificates.
+ is = jarFile.getInputStream(entry);
+ readFullyIgnoringContents(is);
+ return jarFile.getCertificateChains(entry);
+ } catch (IOException | RuntimeException e) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ "Failed reading " + entry.getName() + " in " + jarFile, e);
+ } finally {
+ IoUtils.closeQuietly(is);
+ }
+ }
+
+ private static void readFullyIgnoringContents(InputStream in) throws IOException {
+ byte[] buffer = sBuffer.getAndSet(null);
+ if (buffer == null) {
+ buffer = new byte[4096];
+ }
+
+ int n = 0;
+ int count = 0;
+ while ((n = in.read(buffer, 0, buffer.length)) != -1) {
+ count += n;
+ }
+
+ sBuffer.set(buffer);
+ return;
+ }
+
+ /**
+ * Converts an array of certificate chains into the {@code Signature} equivalent used by the
+ * PackageManager.
+ *
+ * @throws CertificateEncodingException if it is unable to create a Signature object.
+ */
+ public static Signature[] convertToSignatures(Certificate[][] certs)
+ throws CertificateEncodingException {
+ final Signature[] res = new Signature[certs.length];
+ for (int i = 0; i < certs.length; i++) {
+ res[i] = new Signature(certs[i]);
+ }
+ return res;
+ }
+
+ private static void closeQuietly(StrictJarFile jarFile) {
+ if (jarFile != null) {
+ try {
+ jarFile.close();
+ } catch (Exception ignored) {
+ }
+ }
+ }
+
+ /**
+ * Result of a successful APK verification operation.
+ */
+ public static class Result {
+ public final Certificate[][] certs;
+ public final Signature[] sigs;
+
+ public Result(Certificate[][] certs, Signature[] sigs) {
+ this.certs = certs;
+ this.sigs = sigs;
+ }
+ }
+}
diff --git a/core/java/android/service/autofill/IAuthenticationCallback.aidl b/core/java/android/util/apk/SignatureNotFoundException.java
similarity index 61%
copy from core/java/android/service/autofill/IAuthenticationCallback.aidl
copy to core/java/android/util/apk/SignatureNotFoundException.java
index 36b989d..9c7c760 100644
--- a/core/java/android/service/autofill/IAuthenticationCallback.aidl
+++ b/core/java/android/util/apk/SignatureNotFoundException.java
@@ -14,18 +14,21 @@
* limitations under the License.
*/
-package android.view.autofill;
-
-import android.view.autofill.Dataset;
-import android.service.autofill.FillResponse;
+package android.util.apk;
/**
- * Callback for delivering authentication result.
+ * Indicates that the APK is missing a signature.
*
- * {@hide}
+ * @hide
*/
-interface IAutoFillAuthCallback {
- void onSuccessForDataset(in Dataset dataset);
- void onSuccessForFillResponse(in FillResponse response);
- void onFailure(CharSequence message);
+public class SignatureNotFoundException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public SignatureNotFoundException(String message) {
+ super(message);
+ }
+
+ public SignatureNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
}
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/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 9673be0..5bd7446 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -1323,10 +1323,10 @@
public static final int HDR_TYPE_HLG = 3;
/** @hide */
- @IntDef({
- HDR_TYPE_DOLBY_VISION,
- HDR_TYPE_HDR10,
- HDR_TYPE_HLG,
+ @IntDef(prefix = { "HDR_TYPE_" }, value = {
+ HDR_TYPE_DOLBY_VISION,
+ HDR_TYPE_HDR10,
+ HDR_TYPE_HLG,
})
@Retention(RetentionPolicy.SOURCE)
public @interface HdrType {}
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/FrameInfo.java b/core/java/android/view/FrameInfo.java
index c79547c..6c5e048 100644
--- a/core/java/android/view/FrameInfo.java
+++ b/core/java/android/view/FrameInfo.java
@@ -16,7 +16,7 @@
package android.view;
-import android.annotation.IntDef;
+import android.annotation.LongDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -48,7 +48,7 @@
// Is this the first-draw following a window layout?
public static final long FLAG_WINDOW_LAYOUT_CHANGED = 1;
- @IntDef(flag = true, value = {
+ @LongDef(flag = true, value = {
FLAG_WINDOW_LAYOUT_CHANGED })
@Retention(RetentionPolicy.SOURCE)
public @interface FrameInfoFlags {}
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 52e53b0..bc2953e 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -520,162 +520,163 @@
boolean handled = false;
switch (action & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_POINTER_DOWN:
- mDownFocusX = mLastFocusX = focusX;
- mDownFocusY = mLastFocusY = focusY;
- // Cancel long press and taps
- cancelTaps();
- break;
+ case MotionEvent.ACTION_POINTER_DOWN:
+ mDownFocusX = mLastFocusX = focusX;
+ mDownFocusY = mLastFocusY = focusY;
+ // Cancel long press and taps
+ cancelTaps();
+ break;
- case MotionEvent.ACTION_POINTER_UP:
- mDownFocusX = mLastFocusX = focusX;
- mDownFocusY = mLastFocusY = focusY;
+ case MotionEvent.ACTION_POINTER_UP:
+ mDownFocusX = mLastFocusX = focusX;
+ mDownFocusY = mLastFocusY = focusY;
- // Check the dot product of current velocities.
- // If the pointer that left was opposing another velocity vector, clear.
- mVelocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
- final int upIndex = ev.getActionIndex();
- final int id1 = ev.getPointerId(upIndex);
- final float x1 = mVelocityTracker.getXVelocity(id1);
- final float y1 = mVelocityTracker.getYVelocity(id1);
- for (int i = 0; i < count; i++) {
- if (i == upIndex) continue;
+ // Check the dot product of current velocities.
+ // If the pointer that left was opposing another velocity vector, clear.
+ mVelocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
+ final int upIndex = ev.getActionIndex();
+ final int id1 = ev.getPointerId(upIndex);
+ final float x1 = mVelocityTracker.getXVelocity(id1);
+ final float y1 = mVelocityTracker.getYVelocity(id1);
+ for (int i = 0; i < count; i++) {
+ if (i == upIndex) continue;
- final int id2 = ev.getPointerId(i);
- final float x = x1 * mVelocityTracker.getXVelocity(id2);
- final float y = y1 * mVelocityTracker.getYVelocity(id2);
+ final int id2 = ev.getPointerId(i);
+ final float x = x1 * mVelocityTracker.getXVelocity(id2);
+ final float y = y1 * mVelocityTracker.getYVelocity(id2);
- final float dot = x + y;
- if (dot < 0) {
- mVelocityTracker.clear();
+ final float dot = x + y;
+ if (dot < 0) {
+ mVelocityTracker.clear();
+ break;
+ }
+ }
+ break;
+
+ case MotionEvent.ACTION_DOWN:
+ if (mDoubleTapListener != null) {
+ boolean hadTapMessage = mHandler.hasMessages(TAP);
+ if (hadTapMessage) mHandler.removeMessages(TAP);
+ if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null)
+ && hadTapMessage
+ && isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) {
+ // This is a second tap
+ mIsDoubleTapping = true;
+ // Give a callback with the first tap of the double-tap
+ handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent);
+ // Give a callback with down event of the double-tap
+ handled |= mDoubleTapListener.onDoubleTapEvent(ev);
+ } else {
+ // This is a first tap
+ mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT);
+ }
+ }
+
+ mDownFocusX = mLastFocusX = focusX;
+ mDownFocusY = mLastFocusY = focusY;
+ if (mCurrentDownEvent != null) {
+ mCurrentDownEvent.recycle();
+ }
+ mCurrentDownEvent = MotionEvent.obtain(ev);
+ mAlwaysInTapRegion = true;
+ mAlwaysInBiggerTapRegion = true;
+ mStillDown = true;
+ mInLongPress = false;
+ mDeferConfirmSingleTap = false;
+
+ if (mIsLongpressEnabled) {
+ mHandler.removeMessages(LONG_PRESS);
+ mHandler.sendEmptyMessageAtTime(LONG_PRESS,
+ mCurrentDownEvent.getDownTime() + LONGPRESS_TIMEOUT);
+ }
+ mHandler.sendEmptyMessageAtTime(SHOW_PRESS,
+ mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);
+ handled |= mListener.onDown(ev);
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ if (mInLongPress || mInContextClick) {
break;
}
- }
- break;
-
- case MotionEvent.ACTION_DOWN:
- if (mDoubleTapListener != null) {
- boolean hadTapMessage = mHandler.hasMessages(TAP);
- if (hadTapMessage) mHandler.removeMessages(TAP);
- if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage &&
- isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) {
- // This is a second tap
- mIsDoubleTapping = true;
- // Give a callback with the first tap of the double-tap
- handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent);
- // Give a callback with down event of the double-tap
+ final float scrollX = mLastFocusX - focusX;
+ final float scrollY = mLastFocusY - focusY;
+ if (mIsDoubleTapping) {
+ // Give the move events of the double-tap
handled |= mDoubleTapListener.onDoubleTapEvent(ev);
- } else {
- // This is a first tap
- mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT);
- }
- }
-
- mDownFocusX = mLastFocusX = focusX;
- mDownFocusY = mLastFocusY = focusY;
- if (mCurrentDownEvent != null) {
- mCurrentDownEvent.recycle();
- }
- mCurrentDownEvent = MotionEvent.obtain(ev);
- mAlwaysInTapRegion = true;
- mAlwaysInBiggerTapRegion = true;
- mStillDown = true;
- mInLongPress = false;
- mDeferConfirmSingleTap = false;
-
- if (mIsLongpressEnabled) {
- mHandler.removeMessages(LONG_PRESS);
- mHandler.sendEmptyMessageAtTime(LONG_PRESS,
- mCurrentDownEvent.getDownTime() + LONGPRESS_TIMEOUT);
- }
- mHandler.sendEmptyMessageAtTime(SHOW_PRESS,
- mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);
- handled |= mListener.onDown(ev);
- break;
-
- case MotionEvent.ACTION_MOVE:
- if (mInLongPress || mInContextClick) {
- break;
- }
- final float scrollX = mLastFocusX - focusX;
- final float scrollY = mLastFocusY - focusY;
- if (mIsDoubleTapping) {
- // Give the move events of the double-tap
- handled |= mDoubleTapListener.onDoubleTapEvent(ev);
- } else if (mAlwaysInTapRegion) {
- final int deltaX = (int) (focusX - mDownFocusX);
- final int deltaY = (int) (focusY - mDownFocusY);
- int distance = (deltaX * deltaX) + (deltaY * deltaY);
- int slopSquare = isGeneratedGesture ? 0 : mTouchSlopSquare;
- if (distance > slopSquare) {
+ } else if (mAlwaysInTapRegion) {
+ final int deltaX = (int) (focusX - mDownFocusX);
+ final int deltaY = (int) (focusY - mDownFocusY);
+ int distance = (deltaX * deltaX) + (deltaY * deltaY);
+ int slopSquare = isGeneratedGesture ? 0 : mTouchSlopSquare;
+ if (distance > slopSquare) {
+ handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
+ mLastFocusX = focusX;
+ mLastFocusY = focusY;
+ mAlwaysInTapRegion = false;
+ mHandler.removeMessages(TAP);
+ mHandler.removeMessages(SHOW_PRESS);
+ mHandler.removeMessages(LONG_PRESS);
+ }
+ int doubleTapSlopSquare = isGeneratedGesture ? 0 : mDoubleTapTouchSlopSquare;
+ if (distance > doubleTapSlopSquare) {
+ mAlwaysInBiggerTapRegion = false;
+ }
+ } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) {
handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
mLastFocusX = focusX;
mLastFocusY = focusY;
- mAlwaysInTapRegion = false;
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ mStillDown = false;
+ MotionEvent currentUpEvent = MotionEvent.obtain(ev);
+ if (mIsDoubleTapping) {
+ // Finally, give the up event of the double-tap
+ handled |= mDoubleTapListener.onDoubleTapEvent(ev);
+ } else if (mInLongPress) {
mHandler.removeMessages(TAP);
- mHandler.removeMessages(SHOW_PRESS);
- mHandler.removeMessages(LONG_PRESS);
- }
- int doubleTapSlopSquare = isGeneratedGesture ? 0 : mDoubleTapTouchSlopSquare;
- if (distance > doubleTapSlopSquare) {
- mAlwaysInBiggerTapRegion = false;
- }
- } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) {
- handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
- mLastFocusX = focusX;
- mLastFocusY = focusY;
- }
- break;
+ mInLongPress = false;
+ } else if (mAlwaysInTapRegion && !mIgnoreNextUpEvent) {
+ handled = mListener.onSingleTapUp(ev);
+ if (mDeferConfirmSingleTap && mDoubleTapListener != null) {
+ mDoubleTapListener.onSingleTapConfirmed(ev);
+ }
+ } else if (!mIgnoreNextUpEvent) {
- case MotionEvent.ACTION_UP:
- mStillDown = false;
- MotionEvent currentUpEvent = MotionEvent.obtain(ev);
- if (mIsDoubleTapping) {
- // Finally, give the up event of the double-tap
- handled |= mDoubleTapListener.onDoubleTapEvent(ev);
- } else if (mInLongPress) {
- mHandler.removeMessages(TAP);
- mInLongPress = false;
- } else if (mAlwaysInTapRegion && !mIgnoreNextUpEvent) {
- handled = mListener.onSingleTapUp(ev);
- if (mDeferConfirmSingleTap && mDoubleTapListener != null) {
- mDoubleTapListener.onSingleTapConfirmed(ev);
+ // A fling must travel the minimum tap distance
+ final VelocityTracker velocityTracker = mVelocityTracker;
+ final int pointerId = ev.getPointerId(0);
+ velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
+ final float velocityY = velocityTracker.getYVelocity(pointerId);
+ final float velocityX = velocityTracker.getXVelocity(pointerId);
+
+ if ((Math.abs(velocityY) > mMinimumFlingVelocity)
+ || (Math.abs(velocityX) > mMinimumFlingVelocity)) {
+ handled = mListener.onFling(mCurrentDownEvent, ev, velocityX, velocityY);
+ }
}
- } else if (!mIgnoreNextUpEvent) {
-
- // A fling must travel the minimum tap distance
- final VelocityTracker velocityTracker = mVelocityTracker;
- final int pointerId = ev.getPointerId(0);
- velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
- final float velocityY = velocityTracker.getYVelocity(pointerId);
- final float velocityX = velocityTracker.getXVelocity(pointerId);
-
- if ((Math.abs(velocityY) > mMinimumFlingVelocity)
- || (Math.abs(velocityX) > mMinimumFlingVelocity)){
- handled = mListener.onFling(mCurrentDownEvent, ev, velocityX, velocityY);
+ if (mPreviousUpEvent != null) {
+ mPreviousUpEvent.recycle();
}
- }
- if (mPreviousUpEvent != null) {
- mPreviousUpEvent.recycle();
- }
- // Hold the event we obtained above - listeners may have changed the original.
- mPreviousUpEvent = currentUpEvent;
- if (mVelocityTracker != null) {
- // This may have been cleared when we called out to the
- // application above.
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- mIsDoubleTapping = false;
- mDeferConfirmSingleTap = false;
- mIgnoreNextUpEvent = false;
- mHandler.removeMessages(SHOW_PRESS);
- mHandler.removeMessages(LONG_PRESS);
- break;
+ // Hold the event we obtained above - listeners may have changed the original.
+ mPreviousUpEvent = currentUpEvent;
+ if (mVelocityTracker != null) {
+ // This may have been cleared when we called out to the
+ // application above.
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ mIsDoubleTapping = false;
+ mDeferConfirmSingleTap = false;
+ mIgnoreNextUpEvent = false;
+ mHandler.removeMessages(SHOW_PRESS);
+ mHandler.removeMessages(LONG_PRESS);
+ break;
- case MotionEvent.ACTION_CANCEL:
- cancel();
- break;
+ case MotionEvent.ACTION_CANCEL:
+ cancel();
+ break;
}
if (!handled && mInputEventConsistencyVerifier != null) {
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/Surface.java b/core/java/android/view/Surface.java
index ddced6c..a417a4a 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -121,8 +121,12 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({SCALING_MODE_FREEZE, SCALING_MODE_SCALE_TO_WINDOW,
- SCALING_MODE_SCALE_CROP, SCALING_MODE_NO_SCALE_CROP})
+ @IntDef(prefix = { "SCALING_MODE_" }, value = {
+ SCALING_MODE_FREEZE,
+ SCALING_MODE_SCALE_TO_WINDOW,
+ SCALING_MODE_SCALE_CROP,
+ SCALING_MODE_NO_SCALE_CROP
+ })
public @interface ScalingMode {}
// From system/window.h
/** @hide */
@@ -135,7 +139,12 @@
public static final int SCALING_MODE_NO_SCALE_CROP = 3;
/** @hide */
- @IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
+ @IntDef(prefix = { "ROTATION_" }, value = {
+ ROTATION_0,
+ ROTATION_90,
+ ROTATION_180,
+ ROTATION_270
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Rotation {}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index cf05910..268e460 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -16,17 +16,34 @@
package android.view;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+import static android.graphics.Matrix.MSCALE_X;
+import static android.graphics.Matrix.MSCALE_Y;
+import static android.graphics.Matrix.MSKEW_X;
+import static android.graphics.Matrix.MSKEW_Y;
+import static android.graphics.Matrix.MTRANS_X;
+import static android.graphics.Matrix.MTRANS_Y;
+
import android.annotation.Size;
import android.graphics.Bitmap;
import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
+import android.graphics.Matrix;
+import android.graphics.Point;
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.ArrayMap;
import android.util.Log;
import android.view.Surface.OutOfResourcesException;
+
+import com.android.internal.annotations.GuardedBy;
+
import dalvik.system.CloseGuard;
import libcore.util.NativeAllocationRegistry;
@@ -36,12 +53,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);
@@ -139,6 +158,13 @@
private final String mName;
long mNativeObject; // package visibility only for Surface.java access
+ // TODO: Move this to native.
+ private final Object mSizeLock = new Object();
+ @GuardedBy("mSizeLock")
+ private int mWidth;
+ @GuardedBy("mSizeLock")
+ private int mHeight;
+
static Transaction sGlobalTransaction;
static long sTransactionNestCount = 0;
@@ -553,6 +579,8 @@
}
mName = name;
+ mWidth = w;
+ mHeight = h;
mNativeObject = nativeCreate(session, name, w, h, format, flags,
parent != null ? parent.mNativeObject : 0, windowType, ownerUid);
if (mNativeObject == 0) {
@@ -568,12 +596,49 @@
// event logging.
public SurfaceControl(SurfaceControl other) {
mName = other.mName;
+ mWidth = other.mWidth;
+ mHeight = other.mHeight;
mNativeObject = other.mNativeObject;
other.mCloseGuard.close();
other.mNativeObject = 0;
mCloseGuard.open("release");
}
+ private SurfaceControl(Parcel in) {
+ mName = in.readString();
+ mWidth = in.readInt();
+ mHeight = in.readInt();
+ 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);
+ dest.writeInt(mWidth);
+ dest.writeInt(mHeight);
+ 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 +729,7 @@
*/
@Deprecated
public static void mergeToGlobalTransaction(Transaction t) {
- synchronized(sGlobalTransaction) {
+ synchronized(SurfaceControl.class) {
sGlobalTransaction.merge(t);
}
}
@@ -824,6 +889,22 @@
}
}
+ /**
+ * Sets the transform and position of a {@link SurfaceControl} from a 3x3 transformation matrix.
+ *
+ * @param matrix The matrix to apply.
+ * @param float9 An array of 9 floats to be used to extract the values from the matrix.
+ */
+ public void setMatrix(Matrix matrix, float[] float9) {
+ checkNotReleased();
+ matrix.getValues(float9);
+ synchronized (SurfaceControl.class) {
+ sGlobalTransaction.setMatrix(this, float9[MSCALE_X], float9[MSKEW_Y],
+ float9[MSKEW_X], float9[MSCALE_Y]);
+ sGlobalTransaction.setPosition(this, float9[MTRANS_X], float9[MTRANS_Y]);
+ }
+ }
+
public void setWindowCrop(Rect crop) {
checkNotReleased();
synchronized (SurfaceControl.class) {
@@ -861,6 +942,18 @@
}
}
+ public int getWidth() {
+ synchronized (mSizeLock) {
+ return mWidth;
+ }
+ }
+
+ public int getHeight() {
+ synchronized (mSizeLock) {
+ return mHeight;
+ }
+ }
+
@Override
public String toString() {
return "Surface(name=" + mName + ")/@0x" +
@@ -1088,7 +1181,9 @@
}
/**
- * Copy the current screen contents into a bitmap and return it.
+ * Copy the current screen contents into a hardware bitmap and return it.
+ * Note: If you want to modify the Bitmap in software, you will need to copy the Bitmap into
+ * a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)}
*
* CAVEAT: Versions of screenshot that return a {@link Bitmap} can
* be extremely slow; avoid use unless absolutely necessary; prefer
@@ -1113,7 +1208,7 @@
* 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
+ * @return Returns a hardware 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.
*/
@@ -1141,23 +1236,36 @@
}
/**
- * Like {@link SurfaceControl#screenshot(int, int, int, int, boolean)} but
- * includes all Surfaces in the screenshot.
+ * Like {@link SurfaceControl#screenshot(Rect, int, int, int, int, boolean, int)} but
+ * 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,8 +1281,19 @@
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}.
+ * Captures a layer and its children and returns a {@link GraphicBuffer} with the content.
*
* @param layerHandleToken The root layer to capture.
* @param sourceCrop The portion of the root surface to capture; caller may pass in 'new
@@ -1195,6 +1314,7 @@
nativeGetNativeTransactionFinalizer(), 512);
private long mNativeObject;
+ private final ArrayMap<SurfaceControl, Point> mResizedSurfaces = new ArrayMap<>();
Runnable mFreeNativeResources;
public Transaction() {
@@ -1225,9 +1345,22 @@
* Jankier version of apply. Avoid use (b/28068298).
*/
public void apply(boolean sync) {
+ applyResizedSurfaces();
nativeApplyTransaction(mNativeObject, sync);
}
+ private void applyResizedSurfaces() {
+ for (int i = mResizedSurfaces.size() - 1; i >= 0; i--) {
+ final Point size = mResizedSurfaces.valueAt(i);
+ final SurfaceControl surfaceControl = mResizedSurfaces.keyAt(i);
+ synchronized (surfaceControl.mSizeLock) {
+ surfaceControl.mWidth = size.x;
+ surfaceControl.mHeight = size.y;
+ }
+ }
+ mResizedSurfaces.clear();
+ }
+
public Transaction show(SurfaceControl sc) {
sc.checkNotReleased();
nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
@@ -1248,6 +1381,7 @@
public Transaction setSize(SurfaceControl sc, int w, int h) {
sc.checkNotReleased();
+ mResizedSurfaces.put(sc, new Point(w, h));
nativeSetSize(mNativeObject, sc.mNativeObject, w, h);
return this;
}
@@ -1286,6 +1420,14 @@
return this;
}
+ public Transaction setMatrix(SurfaceControl sc, Matrix matrix, float[] float9) {
+ matrix.getValues(float9);
+ setMatrix(sc, float9[MSCALE_X], float9[MSKEW_Y],
+ float9[MSKEW_X], float9[MSCALE_Y]);
+ setPosition(sc, float9[MTRANS_X], float9[MTRANS_Y]);
+ return this;
+ }
+
public Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
sc.checkNotReleased();
if (crop != null) {
@@ -1472,6 +1614,8 @@
* other transaction as if it had been applied.
*/
public Transaction merge(Transaction other) {
+ mResizedSurfaces.putAll(other.mResizedSurfaces);
+ other.mResizedSurfaces.clear();
nativeMergeTransaction(mNativeObject, other.mNativeObject);
return this;
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 7c76bab..6a8f8b1 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();
@@ -333,8 +344,10 @@
private static final int FLAG_DUMP_FRAMESTATS = 1 << 0;
private static final int FLAG_DUMP_RESET = 1 << 1;
- @IntDef(flag = true, value = {
- FLAG_DUMP_FRAMESTATS, FLAG_DUMP_RESET })
+ @IntDef(flag = true, prefix = { "FLAG_DUMP_" }, value = {
+ FLAG_DUMP_FRAMESTATS,
+ FLAG_DUMP_RESET
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface DumpFlags {}
@@ -955,6 +968,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 +1023,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 +1098,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 345e300..ab5372a 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)
@@ -1169,7 +1178,7 @@
private AutofillId mAutofillId;
/** @hide */
- @IntDef({
+ @IntDef(prefix = { "AUTOFILL_TYPE_" }, value = {
AUTOFILL_TYPE_NONE,
AUTOFILL_TYPE_TEXT,
AUTOFILL_TYPE_TOGGLE,
@@ -1240,7 +1249,7 @@
public static final int AUTOFILL_TYPE_DATE = 4;
/** @hide */
- @IntDef({
+ @IntDef(prefix = { "IMPORTANT_FOR_AUTOFILL_" }, value = {
IMPORTANT_FOR_AUTOFILL_AUTO,
IMPORTANT_FOR_AUTOFILL_YES,
IMPORTANT_FOR_AUTOFILL_NO,
@@ -1291,9 +1300,9 @@
public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8;
/** @hide */
- @IntDef(
- flag = true,
- value = {AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS})
+ @IntDef(flag = true, prefix = { "AUTOFILL_FLAG_" }, value = {
+ AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface AutofillFlags {}
@@ -1443,7 +1452,11 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO})
+ @IntDef(prefix = { "DRAWING_CACHE_QUALITY_" }, value = {
+ DRAWING_CACHE_QUALITY_LOW,
+ DRAWING_CACHE_QUALITY_HIGH,
+ DRAWING_CACHE_QUALITY_AUTO
+ })
public @interface DrawingCacheQuality {}
/**
@@ -1542,13 +1555,12 @@
*/
static final int CONTEXT_CLICKABLE = 0x00800000;
-
/** @hide */
- @IntDef({
- SCROLLBARS_INSIDE_OVERLAY,
- SCROLLBARS_INSIDE_INSET,
- SCROLLBARS_OUTSIDE_OVERLAY,
- SCROLLBARS_OUTSIDE_INSET
+ @IntDef(prefix = { "SCROLLBARS_" }, value = {
+ SCROLLBARS_INSIDE_OVERLAY,
+ SCROLLBARS_INSIDE_INSET,
+ SCROLLBARS_OUTSIDE_OVERLAY,
+ SCROLLBARS_OUTSIDE_INSET
})
@Retention(RetentionPolicy.SOURCE)
public @interface ScrollBarStyle {}
@@ -1642,11 +1654,10 @@
static final int TOOLTIP = 0x40000000;
/** @hide */
- @IntDef(flag = true,
- value = {
- FOCUSABLES_ALL,
- FOCUSABLES_TOUCH_MODE
- })
+ @IntDef(flag = true, prefix = { "FOCUSABLES_" }, value = {
+ FOCUSABLES_ALL,
+ FOCUSABLES_TOUCH_MODE
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface FocusableMode {}
@@ -1663,7 +1674,7 @@
public static final int FOCUSABLES_TOUCH_MODE = 0x00000001;
/** @hide */
- @IntDef({
+ @IntDef(prefix = { "FOCUS_" }, value = {
FOCUS_BACKWARD,
FOCUS_FORWARD,
FOCUS_LEFT,
@@ -1675,7 +1686,7 @@
public @interface FocusDirection {}
/** @hide */
- @IntDef({
+ @IntDef(prefix = { "FOCUS_" }, value = {
FOCUS_LEFT,
FOCUS_UP,
FOCUS_RIGHT,
@@ -2417,20 +2428,20 @@
static final int PFLAG2_DRAG_HOVERED = 0x00000002;
/** @hide */
- @IntDef({
- LAYOUT_DIRECTION_LTR,
- LAYOUT_DIRECTION_RTL,
- LAYOUT_DIRECTION_INHERIT,
- LAYOUT_DIRECTION_LOCALE
+ @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = {
+ LAYOUT_DIRECTION_LTR,
+ LAYOUT_DIRECTION_RTL,
+ LAYOUT_DIRECTION_INHERIT,
+ LAYOUT_DIRECTION_LOCALE
})
@Retention(RetentionPolicy.SOURCE)
// Not called LayoutDirection to avoid conflict with android.util.LayoutDirection
public @interface LayoutDir {}
/** @hide */
- @IntDef({
- LAYOUT_DIRECTION_LTR,
- LAYOUT_DIRECTION_RTL
+ @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = {
+ LAYOUT_DIRECTION_LTR,
+ LAYOUT_DIRECTION_RTL
})
@Retention(RetentionPolicy.SOURCE)
public @interface ResolvedLayoutDir {}
@@ -2636,14 +2647,14 @@
TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
/** @hide */
- @IntDef({
- TEXT_ALIGNMENT_INHERIT,
- TEXT_ALIGNMENT_GRAVITY,
- TEXT_ALIGNMENT_CENTER,
- TEXT_ALIGNMENT_TEXT_START,
- TEXT_ALIGNMENT_TEXT_END,
- TEXT_ALIGNMENT_VIEW_START,
- TEXT_ALIGNMENT_VIEW_END
+ @IntDef(prefix = { "TEXT_ALIGNMENT_" }, value = {
+ TEXT_ALIGNMENT_INHERIT,
+ TEXT_ALIGNMENT_GRAVITY,
+ TEXT_ALIGNMENT_CENTER,
+ TEXT_ALIGNMENT_TEXT_START,
+ TEXT_ALIGNMENT_TEXT_END,
+ TEXT_ALIGNMENT_VIEW_START,
+ TEXT_ALIGNMENT_VIEW_END
})
@Retention(RetentionPolicy.SOURCE)
public @interface TextAlignment {}
@@ -3040,15 +3051,14 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- value = {
- SCROLL_INDICATOR_TOP,
- SCROLL_INDICATOR_BOTTOM,
- SCROLL_INDICATOR_LEFT,
- SCROLL_INDICATOR_RIGHT,
- SCROLL_INDICATOR_START,
- SCROLL_INDICATOR_END,
- })
+ @IntDef(flag = true, prefix = { "SCROLL_INDICATOR_" }, value = {
+ SCROLL_INDICATOR_TOP,
+ SCROLL_INDICATOR_BOTTOM,
+ SCROLL_INDICATOR_LEFT,
+ SCROLL_INDICATOR_RIGHT,
+ SCROLL_INDICATOR_START,
+ SCROLL_INDICATOR_END,
+ })
public @interface ScrollIndicators {}
/**
@@ -3674,8 +3684,10 @@
| SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
/** @hide */
- @IntDef(flag = true,
- value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION })
+ @IntDef(flag = true, prefix = { "FIND_VIEWS_" }, value = {
+ FIND_VIEWS_WITH_TEXT,
+ FIND_VIEWS_WITH_CONTENT_DESCRIPTION
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface FindViewFlags {}
@@ -4752,6 +4764,8 @@
sUseDefaultFocusHighlight = context.getResources().getBoolean(
com.android.internal.R.bool.config_useDefaultFocusHighlight);
+ sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P;
+
sCompatibilityDone = true;
}
}
@@ -14272,7 +14286,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);
@@ -14309,7 +14323,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);
@@ -14859,13 +14873,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);
}
/**
@@ -14954,7 +14996,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);
@@ -15047,7 +15089,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);
@@ -25718,6 +25760,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/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1c9d863..c6c42fa 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -20,6 +20,7 @@
import static android.view.View.PFLAG_DRAW_ANIMATION;
import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
+import static android.view.WindowManager.LayoutParams.FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
@@ -142,10 +143,11 @@
private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV;
/**
- * Set to false if we do not want to use the multi threaded renderer. Note that by disabling
+ * Set to false if we do not want to use the multi threaded renderer even though
+ * threaded renderer (aka hardware renderering) is used. Note that by disabling
* this, WindowCallbacks will not fire.
*/
- private static final boolean USE_MT_RENDERER = true;
+ private static final boolean MT_RENDERER_AVAILABLE = true;
/**
* Set this system property to true to force the view hierarchy to render
@@ -302,6 +304,7 @@
Rect mDirty;
public boolean mIsAnimating;
+ private boolean mUseMTRenderer;
private boolean mDragResizing;
private boolean mInvalidateRootRequested;
private int mResizeMode;
@@ -384,12 +387,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;
@@ -545,18 +551,14 @@
}
public void addWindowCallbacks(WindowCallbacks callback) {
- if (USE_MT_RENDERER) {
- synchronized (mWindowCallbacks) {
- mWindowCallbacks.add(callback);
- }
+ synchronized (mWindowCallbacks) {
+ mWindowCallbacks.add(callback);
}
}
public void removeWindowCallbacks(WindowCallbacks callback) {
- if (USE_MT_RENDERER) {
- synchronized (mWindowCallbacks) {
- mWindowCallbacks.remove(callback);
- }
+ synchronized (mWindowCallbacks) {
+ mWindowCallbacks.remove(callback);
}
}
@@ -682,7 +684,17 @@
// If the application owns the surface, don't enable hardware acceleration
if (mSurfaceHolder == null) {
+ // While this is supposed to enable only, it can effectively disable
+ // the acceleration too.
enableHardwareAcceleration(attrs);
+ final boolean useMTRenderer = MT_RENDERER_AVAILABLE
+ && mAttachInfo.mThreadedRenderer != null;
+ if (mUseMTRenderer != useMTRenderer) {
+ // Shouldn't be resizing, as it's done only in window setup,
+ // but end just in case.
+ endDragResizing();
+ mUseMTRenderer = useMTRenderer;
+ }
}
boolean restore = false;
@@ -730,7 +742,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 +764,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 +1557,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,13 +1581,21 @@
mLastWindowInsets = new WindowInsets(contentInsets,
null /* windowDecorInsets */, stableInsets,
mContext.getResources().getConfiguration().isScreenRound(),
- mAttachInfo.mAlwaysConsumeNavBar, null /* displayCutout */);
+ mAttachInfo.mAlwaysConsumeNavBar, displayCutout);
}
return mLastWindowInsets;
}
void dispatchApplyInsets(View host) {
- host.dispatchApplyWindowInsets(getWindowInsets(true /* forceConstruct */));
+ WindowInsets insets = getWindowInsets(true /* forceConstruct */);
+ final boolean layoutInCutout =
+ (mWindowAttributes.flags2 & FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA) != 0;
+ if (!layoutInCutout) {
+ // Window is either not laid out in cutout or the status bar inset takes care of
+ // clearing the cutout, so we don't need to dispatch the cutout to the hierarchy.
+ insets = insets.consumeCutout();
+ }
+ host.dispatchApplyWindowInsets(insets);
}
private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) {
@@ -1730,6 +1756,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 +1935,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 +1961,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 +1987,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 +2096,7 @@
mResizeMode = freeformResizing
? RESIZE_MODE_FREEFORM
: RESIZE_MODE_DOCKED_DIVIDER;
+ // TODO: Need cutout?
startDragResizing(mPendingBackDropFrame,
mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
mPendingStableInsets, mResizeMode);
@@ -2064,7 +2105,7 @@
endDragResizing();
}
}
- if (!USE_MT_RENDERER) {
+ if (!mUseMTRenderer) {
if (dragResizing) {
mCanvasOffsetX = mWinFrame.left;
mCanvasOffsetY = mWinFrame.top;
@@ -2702,8 +2743,10 @@
@Override
public void onPostDraw(DisplayListCanvas canvas) {
drawAccessibilityFocusedDrawableIfNeeded(canvas);
- for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
- mWindowCallbacks.get(i).onPostDraw(canvas);
+ if (mUseMTRenderer) {
+ for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+ mWindowCallbacks.get(i).onPostDraw(canvas);
+ }
}
}
@@ -3034,7 +3077,8 @@
return;
}
- if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
+ if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
+ scalingRequired, dirty, surfaceInsets)) {
return;
}
}
@@ -3050,11 +3094,22 @@
* @return true if drawing was successful, false if an error occurred
*/
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
- boolean scalingRequired, Rect dirty) {
+ boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
// Draw with software renderer.
final Canvas canvas;
+
+ // We already have the offset of surfaceInsets in xoff, yoff and dirty region,
+ // therefore we need to add it back when moving the dirty region.
+ int dirtyXOffset = xoff;
+ int dirtyYOffset = yoff;
+ if (surfaceInsets != null) {
+ dirtyXOffset += surfaceInsets.left;
+ dirtyYOffset += surfaceInsets.top;
+ }
+
try {
+ dirty.offset(-dirtyXOffset, -dirtyYOffset);
final int left = dirty.left;
final int top = dirty.top;
final int right = dirty.right;
@@ -3081,6 +3136,8 @@
// kill stuff (or ourself) for no reason.
mLayoutRequested = true; // ask wm for a new surface next time.
return false;
+ } finally {
+ dirty.offset(dirtyXOffset, dirtyYOffset); // Reset to the original value.
}
try {
@@ -3776,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)
&& mPendingBackDropFrame.equals(args.arg8)
@@ -3808,6 +3866,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 +3874,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 +6318,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 +6601,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()
@@ -6550,7 +6611,7 @@
// Tell all listeners that we are resizing the window so that the chrome can get
// updated as fast as possible on a separate thread,
- if (mDragResizing) {
+ if (mDragResizing && mUseMTRenderer) {
boolean fullscreen = frame.equals(backDropFrame);
synchronized (mWindowCallbacks) {
for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
@@ -6578,6 +6639,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 +7672,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);
}
}
@@ -7798,9 +7861,11 @@
Rect stableInsets, int resizeMode) {
if (!mDragResizing) {
mDragResizing = true;
- for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
- mWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds, fullscreen,
- systemInsets, stableInsets, resizeMode);
+ if (mUseMTRenderer) {
+ for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+ mWindowCallbacks.get(i).onWindowDragResizeStart(
+ initialBounds, fullscreen, systemInsets, stableInsets, resizeMode);
+ }
}
mFullRedrawNeeded = true;
}
@@ -7812,8 +7877,10 @@
private void endDragResizing() {
if (mDragResizing) {
mDragResizing = false;
- for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
- mWindowCallbacks.get(i).onWindowDragResizeEnd();
+ if (mUseMTRenderer) {
+ for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+ mWindowCallbacks.get(i).onWindowDragResizeEnd();
+ }
}
mFullRedrawNeeded = true;
}
@@ -7821,19 +7888,21 @@
private boolean updateContentDrawBounds() {
boolean updated = false;
- for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
- updated |= mWindowCallbacks.get(i).onContentDrawn(
- mWindowAttributes.surfaceInsets.left,
- mWindowAttributes.surfaceInsets.top,
- mWidth, mHeight);
+ if (mUseMTRenderer) {
+ for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+ updated |=
+ mWindowCallbacks.get(i).onContentDrawn(mWindowAttributes.surfaceInsets.left,
+ mWindowAttributes.surfaceInsets.top, mWidth, mHeight);
+ }
}
return updated | (mDragResizing && mReportNextDraw);
}
private void requestDrawWindow() {
- if (mReportNextDraw) {
- mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
+ if (!mUseMTRenderer) {
+ return;
}
+ mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
}
@@ -7877,6 +7946,7 @@
if (!registered) {
mAttachInfo.mAccessibilityWindowId =
mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
+ mContext.getPackageName(),
new AccessibilityInteractionConnection(ViewRootImpl.this));
}
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 905c071..012e864 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -20,6 +20,7 @@
import android.Manifest.permission;
import android.annotation.IntDef;
+import android.annotation.LongDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
@@ -1268,6 +1269,35 @@
}, formatToHexString = true)
public int flags;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @LongDef(
+ 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
@@ -1642,12 +1672,20 @@
* Visibility state for {@link #softInputMode}: please show the soft
* input area when normally appropriate (when the user is navigating
* forward to your window).
+ *
+ * <p>Applications that target {@link android.os.Build.VERSION_CODES#P} and later, this flag
+ * is ignored unless there is a focused view that returns {@code true} from
+ * {@link View#isInEditMode()} when the window is focused.</p>
*/
public static final int SOFT_INPUT_STATE_VISIBLE = 4;
/**
* Visibility state for {@link #softInputMode}: please always make the
* soft input area visible when this window receives input focus.
+ *
+ * <p>Applications that target {@link android.os.Build.VERSION_CODES#P} and later, this flag
+ * is ignored unless there is a focused view that returns {@code true} from
+ * {@link View#isInEditMode()} when the window is focused.</p>
*/
public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;
@@ -1708,7 +1746,7 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {
+ @IntDef(flag = true, prefix = { "SOFT_INPUT_" }, value = {
SOFT_INPUT_STATE_UNSPECIFIED,
SOFT_INPUT_STATE_UNCHANGED,
SOFT_INPUT_STATE_HIDDEN,
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 d890f32..72af203 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -29,6 +29,7 @@
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
import java.util.Collections;
@@ -213,7 +214,7 @@
*
* @param connectionId The id of a connection for interacting with the system.
* @param accessibilityWindowId A unique window id. Use
- * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+ * {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
* to query the currently active window.
* @return The {@link AccessibilityWindowInfo}.
*/
@@ -299,7 +300,7 @@
*
* @param connectionId The id of a connection for interacting with the system.
* @param accessibilityWindowId A unique window id. Use
- * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+ * {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
* to query the currently active window.
* @param accessibilityNodeId A unique view id or virtual descendant id from
* where to start the search. Use
@@ -335,18 +336,19 @@
}
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success;
+ final String[] packageNames;
try {
- success = connection.findAccessibilityNodeInfoByAccessibilityId(
+ packageNames = connection.findAccessibilityNodeInfoByAccessibilityId(
accessibilityWindowId, accessibilityNodeId, interactionId, this,
prefetchFlags, Thread.currentThread().getId(), arguments);
} finally {
Binder.restoreCallingIdentity(identityToken);
}
- if (success) {
+ if (packageNames != null) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
- finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, bypassCache);
+ finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
+ bypassCache, packageNames);
if (infos != null && !infos.isEmpty()) {
for (int i = 1; i < infos.size(); i++) {
infos.get(i).recycle();
@@ -373,7 +375,7 @@
*
* @param connectionId The id of a connection for interacting with the system.
* @param accessibilityWindowId A unique window id. Use
- * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+ * {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
* to query the currently active window.
* @param accessibilityNodeId A unique view id or virtual descendant id from
* where to start the search. Use
@@ -389,20 +391,21 @@
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success;
+ final String[] packageNames;
try {
- success = connection.findAccessibilityNodeInfosByViewId(
+ packageNames = connection.findAccessibilityNodeInfosByViewId(
accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
Thread.currentThread().getId());
} finally {
Binder.restoreCallingIdentity(identityToken);
}
- if (success) {
+ if (packageNames != null) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
if (infos != null) {
- finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, false);
+ finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
+ false, packageNames);
return infos;
}
}
@@ -426,7 +429,7 @@
*
* @param connectionId The id of a connection for interacting with the system.
* @param accessibilityWindowId A unique window id. Use
- * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+ * {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
* to query the currently active window.
* @param accessibilityNodeId A unique view id or virtual descendant id from
* where to start the search. Use
@@ -442,20 +445,21 @@
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success;
+ final String[] packageNames;
try {
- success = connection.findAccessibilityNodeInfosByText(
+ packageNames = connection.findAccessibilityNodeInfosByText(
accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
Thread.currentThread().getId());
} finally {
Binder.restoreCallingIdentity(identityToken);
}
- if (success) {
+ if (packageNames != null) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
if (infos != null) {
- finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, false);
+ finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
+ false, packageNames);
return infos;
}
}
@@ -478,7 +482,7 @@
*
* @param connectionId The id of a connection for interacting with the system.
* @param accessibilityWindowId A unique window id. Use
- * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+ * {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
* to query the currently active window.
* @param accessibilityNodeId A unique view id or virtual descendant id from
* where to start the search. Use
@@ -494,19 +498,19 @@
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success;
+ final String[] packageNames;
try {
- success = connection.findFocus(accessibilityWindowId,
+ packageNames = connection.findFocus(accessibilityWindowId,
accessibilityNodeId, focusType, interactionId, this,
Thread.currentThread().getId());
} finally {
Binder.restoreCallingIdentity(identityToken);
}
- if (success) {
+ if (packageNames != null) {
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
interactionId);
- finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false);
+ finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false, packageNames);
return info;
}
} else {
@@ -527,7 +531,7 @@
*
* @param connectionId The id of a connection for interacting with the system.
* @param accessibilityWindowId A unique window id. Use
- * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+ * {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
* to query the currently active window.
* @param accessibilityNodeId A unique view id or virtual descendant id from
* where to start the search. Use
@@ -543,19 +547,19 @@
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success;
+ final String[] packageNames;
try {
- success = connection.focusSearch(accessibilityWindowId,
+ packageNames = connection.focusSearch(accessibilityWindowId,
accessibilityNodeId, direction, interactionId, this,
Thread.currentThread().getId());
} finally {
Binder.restoreCallingIdentity(identityToken);
}
- if (success) {
+ if (packageNames != null) {
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
interactionId);
- finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false);
+ finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false, packageNames);
return info;
}
} else {
@@ -574,7 +578,7 @@
*
* @param connectionId The id of a connection for interacting with the system.
* @param accessibilityWindowId A unique window id. Use
- * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+ * {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
* to query the currently active window.
* @param accessibilityNodeId A unique view id or virtual descendant id from
* where to start the search. Use
@@ -661,7 +665,7 @@
int interactionId) {
synchronized (mInstanceLock) {
final boolean success = waitForResultTimedLocked(interactionId);
- List<AccessibilityNodeInfo> result = null;
+ final List<AccessibilityNodeInfo> result;
if (success) {
result = mFindAccessibilityNodeInfosResult;
} else {
@@ -779,11 +783,22 @@
* @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}
+ * @param packageNames The valid package names a node can come from.
*/
private void finalizeAndCacheAccessibilityNodeInfo(AccessibilityNodeInfo info,
- int connectionId, boolean bypassCache) {
+ int connectionId, boolean bypassCache, String[] packageNames) {
if (info != null) {
info.setConnectionId(connectionId);
+ // Empty array means any package name is Okay
+ if (!ArrayUtils.isEmpty(packageNames)) {
+ CharSequence packageName = info.getPackageName();
+ if (packageName == null
+ || !ArrayUtils.contains(packageNames, packageName.toString())) {
+ // If the node package not one of the valid ones, pick the top one - this
+ // is one of the packages running in the introspected UID.
+ info.setPackageName(packageNames[0]);
+ }
+ }
info.setSealed(true);
if (!bypassCache) {
sAccessibilityCache.add(info);
@@ -798,14 +813,16 @@
* @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}
+ * @param packageNames The valid package names a node can come from.
*/
private void finalizeAndCacheAccessibilityNodeInfos(List<AccessibilityNodeInfo> infos,
- int connectionId, boolean bypassCache) {
+ int connectionId, boolean bypassCache, String[] packageNames) {
if (infos != null) {
final int infosCount = infos.size();
for (int i = 0; i < infosCount; i++) {
AccessibilityNodeInfo info = infos.get(i);
- finalizeAndCacheAccessibilityNodeInfo(info, connectionId, bypassCache);
+ finalizeAndCacheAccessibilityNodeInfo(info, connectionId,
+ bypassCache, packageNames);
}
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 35f6acb..b4499d1 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -888,7 +888,7 @@
* @hide
*/
public int addAccessibilityInteractionConnection(IWindow windowToken,
- IAccessibilityInteractionConnection connection) {
+ String packageName, IAccessibilityInteractionConnection connection) {
final IAccessibilityManager service;
final int userId;
synchronized (mLock) {
@@ -899,7 +899,8 @@
userId = mUserId;
}
try {
- return service.addAccessibilityInteractionConnection(windowToken, connection, userId);
+ return service.addAccessibilityInteractionConnection(windowToken, connection,
+ packageName, userId);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error while adding an accessibility interaction connection. ", re);
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index faea920..9c2f6bb 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -3695,8 +3695,9 @@
if (DEBUG) {
builder.append("; sourceNodeId: " + mSourceNodeId);
- builder.append("; accessibilityViewId: " + getAccessibilityViewId(mSourceNodeId));
- builder.append("; virtualDescendantId: " + getVirtualDescendantId(mSourceNodeId));
+ builder.append("; windowId: " + mWindowId);
+ builder.append("; accessibilityViewId: ").append(getAccessibilityViewId(mSourceNodeId));
+ builder.append("; virtualDescendantId: ").append(getVirtualDescendantId(mSourceNodeId));
builder.append("; mParentNodeId: " + mParentNodeId);
builder.append("; traversalBefore: ").append(mTraversalBefore);
builder.append("; traversalAfter: ").append(mTraversalAfter);
@@ -3726,8 +3727,8 @@
builder.append("]");
}
- builder.append("; boundsInParent: " + mBoundsInParent);
- builder.append("; boundsInScreen: " + mBoundsInScreen);
+ builder.append("; boundsInParent: ").append(mBoundsInParent);
+ builder.append("; boundsInScreen: ").append(mBoundsInScreen);
builder.append("; packageName: ").append(mPackageName);
builder.append("; className: ").append(mClassName);
diff --git a/core/java/android/view/accessibility/AccessibilityRequestPreparer.java b/core/java/android/view/accessibility/AccessibilityRequestPreparer.java
index 889feb9..25f830a 100644
--- a/core/java/android/view/accessibility/AccessibilityRequestPreparer.java
+++ b/core/java/android/view/accessibility/AccessibilityRequestPreparer.java
@@ -44,10 +44,9 @@
public static final int REQUEST_TYPE_EXTRA_DATA = 0x00000001;
/** @hide */
- @IntDef(flag = true,
- value = {
- REQUEST_TYPE_EXTRA_DATA
- })
+ @IntDef(flag = true, prefix = { "REQUEST_TYPE_" }, value = {
+ REQUEST_TYPE_EXTRA_DATA
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface RequestTypes {}
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 3f499ab..c93e2c1 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -45,7 +45,8 @@
List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, int userId);
int addAccessibilityInteractionConnection(IWindow windowToken,
- in IAccessibilityInteractionConnection connection, int userId);
+ in IAccessibilityInteractionConnection connection,
+ String packageName, int userId);
void removeAccessibilityInteractionConnection(IWindow windowToken);
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 547e0db..6d84aa0 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) {
@@ -1918,7 +1987,11 @@
public abstract static class AutofillCallback {
/** @hide */
- @IntDef({EVENT_INPUT_SHOWN, EVENT_INPUT_HIDDEN, EVENT_INPUT_UNAVAILABLE})
+ @IntDef(prefix = { "EVENT_INPUT_" }, value = {
+ EVENT_INPUT_SHOWN,
+ EVENT_INPUT_HIDDEN,
+ EVENT_INPUT_UNAVAILABLE
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface AutofillEventType {}
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..9f033d7 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -24,6 +24,7 @@
import android.annotation.SystemService;
import android.content.Context;
import android.graphics.Rect;
+import android.inputmethodservice.InputMethodService;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -697,6 +698,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();
@@ -722,7 +736,20 @@
}
}
+ /**
+ * @deprecated Use {@link InputMethodService#showStatusIcon(int)} instead. This method was
+ * intended for IME developers who should be accessing APIs through the service. APIs in this
+ * class are intended for app developers interacting with the IME.
+ */
+ @Deprecated
public void showStatusIcon(IBinder imeToken, String packageName, int iconId) {
+ showStatusIconInternal(imeToken, packageName, iconId);
+ }
+
+ /**
+ * @hide
+ */
+ public void showStatusIconInternal(IBinder imeToken, String packageName, int iconId) {
try {
mService.updateStatusIcon(imeToken, packageName, iconId);
} catch (RemoteException e) {
@@ -730,7 +757,20 @@
}
}
+ /**
+ * @deprecated Use {@link InputMethodService#hideStatusIcon()} instead. This method was
+ * intended for IME developers who should be accessing APIs through the service. APIs in
+ * this class are intended for app developers interacting with the IME.
+ */
+ @Deprecated
public void hideStatusIcon(IBinder imeToken) {
+ hideStatusIconInternal(imeToken);
+ }
+
+ /**
+ * @hide
+ */
+ public void hideStatusIconInternal(IBinder imeToken) {
try {
mService.updateStatusIcon(imeToken, null, 0);
} catch (RemoteException e) {
@@ -1108,7 +1148,6 @@
}
}
-
/**
* This method toggles the input method window display.
* If the input window is already displayed, it gets hidden.
@@ -1294,7 +1333,8 @@
+ Integer.toHexString(controlFlags));
final InputBindResult res = mService.startInputOrWindowGainedFocus(
startInputReason, mClient, windowGainingFocus, controlFlags, softInputMode,
- windowFlags, tba, servedContext, missingMethodFlags);
+ windowFlags, tba, servedContext, missingMethodFlags,
+ view.getContext().getApplicationInfo().targetSdkVersion);
if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
if (res != null) {
if (res.id != null) {
@@ -1549,7 +1589,8 @@
mService.startInputOrWindowGainedFocus(
InputMethodClient.START_INPUT_REASON_WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
rootView.getWindowToken(), controlFlags, softInputMode, windowFlags, null,
- null, 0 /* missingMethodFlags */);
+ null, 0 /* missingMethodFlags */,
+ rootView.getContext().getApplicationInfo().targetSdkVersion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1787,8 +1828,19 @@
* when it was started, which allows it to perform this operation on
* itself.
* @param id The unique identifier for the new input method to be switched to.
+ * @deprecated Use {@link InputMethodService#setInputMethod(String)} instead. This method
+ * was intended for IME developers who should be accessing APIs through the service. APIs in
+ * this class are intended for app developers interacting with the IME.
*/
+ @Deprecated
public void setInputMethod(IBinder token, String id) {
+ setInputMethodInternal(token, id);
+ }
+
+ /**
+ * @hide
+ */
+ public void setInputMethodInternal(IBinder token, String id) {
try {
mService.setInputMethod(token, id);
} catch (RemoteException e) {
@@ -1804,8 +1856,21 @@
* itself.
* @param id The unique identifier for the new input method to be switched to.
* @param subtype The new subtype of the new input method to be switched to.
+ * @deprecated Use
+ * {@link InputMethodService#setInputMethodAndSubtype(String, InputMethodSubtype)}
+ * instead. This method was intended for IME developers who should be accessing APIs through
+ * the service. APIs in this class are intended for app developers interacting with the IME.
*/
+ @Deprecated
public void setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype) {
+ setInputMethodAndSubtypeInternal(token, id, subtype);
+ }
+
+ /**
+ * @hide
+ */
+ public void setInputMethodAndSubtypeInternal(
+ IBinder token, String id, InputMethodSubtype subtype) {
try {
mService.setInputMethodAndSubtype(token, id, subtype);
} catch (RemoteException e) {
@@ -1824,8 +1889,19 @@
* @param flags Provides additional operating flags. Currently may be
* 0 or have the {@link #HIDE_IMPLICIT_ONLY},
* {@link #HIDE_NOT_ALWAYS} bit set.
+ * @deprecated Use {@link InputMethodService#hideSoftInputFromInputMethod(int)}
+ * instead. This method was intended for IME developers who should be accessing APIs through
+ * the service. APIs in this class are intended for app developers interacting with the IME.
*/
+ @Deprecated
public void hideSoftInputFromInputMethod(IBinder token, int flags) {
+ hideSoftInputFromInputMethodInternal(token, flags);
+ }
+
+ /**
+ * @hide
+ */
+ public void hideSoftInputFromInputMethodInternal(IBinder token, int flags) {
try {
mService.hideMySoftInput(token, flags);
} catch (RemoteException e) {
@@ -1845,8 +1921,19 @@
* @param flags Provides additional operating flags. Currently may be
* 0 or have the {@link #SHOW_IMPLICIT} or
* {@link #SHOW_FORCED} bit set.
+ * @deprecated Use {@link InputMethodService#showSoftInputFromInputMethod(int)}
+ * instead. This method was intended for IME developers who should be accessing APIs through
+ * the service. APIs in this class are intended for app developers interacting with the IME.
*/
+ @Deprecated
public void showSoftInputFromInputMethod(IBinder token, int flags) {
+ showSoftInputFromInputMethodInternal(token, flags);
+ }
+
+ /**
+ * @hide
+ */
+ public void showSoftInputFromInputMethodInternal(IBinder token, int flags) {
try {
mService.showMySoftInput(token, flags);
} catch (RemoteException e) {
@@ -2226,8 +2313,19 @@
* which allows it to perform this operation on itself.
* @return true if the current input method and subtype was successfully switched to the last
* used input method and subtype.
+ * @deprecated Use {@link InputMethodService#switchToLastInputMethod()} instead. This method
+ * was intended for IME developers who should be accessing APIs through the service. APIs in
+ * this class are intended for app developers interacting with the IME.
*/
+ @Deprecated
public boolean switchToLastInputMethod(IBinder imeToken) {
+ return switchToLastInputMethodInternal(imeToken);
+ }
+
+ /**
+ * @hide
+ */
+ public boolean switchToLastInputMethodInternal(IBinder imeToken) {
synchronized (mH) {
try {
return mService.switchToLastInputMethod(imeToken);
@@ -2246,8 +2344,19 @@
* belongs to the current IME
* @return true if the current input method and subtype was successfully switched to the next
* input method and subtype.
+ * @deprecated Use {@link InputMethodService#switchToNextInputMethod(boolean)} instead. This
+ * method was intended for IME developers who should be accessing APIs through the service.
+ * APIs in this class are intended for app developers interacting with the IME.
*/
+ @Deprecated
public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) {
+ return switchToNextInputMethodInternal(imeToken, onlyCurrentIme);
+ }
+
+ /**
+ * @hide
+ */
+ public boolean switchToNextInputMethodInternal(IBinder imeToken, boolean onlyCurrentIme) {
synchronized (mH) {
try {
return mService.switchToNextInputMethod(imeToken, onlyCurrentIme);
@@ -2267,8 +2376,19 @@
* between IMEs and subtypes.
* @param imeToken Supplies the identifying token given to an input method when it was started,
* which allows it to perform this operation on itself.
+ * @deprecated Use {@link InputMethodService#shouldOfferSwitchingToNextInputMethod()}
+ * instead. This method was intended for IME developers who should be accessing APIs through
+ * the service. APIs in this class are intended for app developers interacting with the IME.
*/
+ @Deprecated
public boolean shouldOfferSwitchingToNextInputMethod(IBinder imeToken) {
+ return shouldOfferSwitchingToNextInputMethodInternal(imeToken);
+ }
+
+ /**
+ * @hide
+ */
+ public boolean shouldOfferSwitchingToNextInputMethodInternal(IBinder imeToken) {
synchronized (mH) {
try {
return mService.shouldOfferSwitchingToNextInputMethod(imeToken);
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..fdc9f92 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";
@@ -47,8 +48,13 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @StringDef({
- TYPE_UNKNOWN, TYPE_OTHER, TYPE_EMAIL, TYPE_PHONE, TYPE_ADDRESS, TYPE_URL
+ @StringDef(prefix = { "TYPE_" }, value = {
+ TYPE_UNKNOWN,
+ TYPE_OTHER,
+ TYPE_EMAIL,
+ TYPE_PHONE,
+ TYPE_ADDRESS,
+ TYPE_URL,
})
@interface EntityType {}
@@ -70,6 +76,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 +86,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 +133,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 +151,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 +161,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 +207,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 +218,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 +267,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..d7aaee7 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, classifiedText));
- 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/WebSettings.java b/core/java/android/webkit/WebSettings.java
index e493739..90cc481 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -122,7 +122,13 @@
}
/** @hide */
- @IntDef({LOAD_DEFAULT, LOAD_NORMAL, LOAD_CACHE_ELSE_NETWORK, LOAD_NO_CACHE, LOAD_CACHE_ONLY})
+ @IntDef(prefix = { "LOAD_" }, value = {
+ LOAD_DEFAULT,
+ LOAD_NORMAL,
+ LOAD_CACHE_ELSE_NETWORK,
+ LOAD_NO_CACHE,
+ LOAD_CACHE_ONLY
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface CacheMode {}
@@ -1415,13 +1421,12 @@
/**
* @hide
*/
- @IntDef(flag = true,
- value = {
- MENU_ITEM_NONE,
- MENU_ITEM_SHARE,
- MENU_ITEM_WEB_SEARCH,
- MENU_ITEM_PROCESS_TEXT
- })
+ @IntDef(flag = true, prefix = { "MENU_ITEM_" }, value = {
+ MENU_ITEM_NONE,
+ MENU_ITEM_SHARE,
+ MENU_ITEM_WEB_SEARCH,
+ MENU_ITEM_PROCESS_TEXT
+ })
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.PARAMETER, ElementType.METHOD})
private @interface MenuItemFlags {}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6f99254..d39c1e1 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2249,10 +2249,10 @@
}
/** @hide */
- @IntDef({
- RENDERER_PRIORITY_WAIVED,
- RENDERER_PRIORITY_BOUND,
- RENDERER_PRIORITY_IMPORTANT
+ @IntDef(prefix = { "RENDERER_PRIORITY_" }, value = {
+ RENDERER_PRIORITY_WAIVED,
+ RENDERER_PRIORITY_BOUND,
+ RENDERER_PRIORITY_IMPORTANT
})
@Retention(RetentionPolicy.SOURCE)
public @interface RendererPriority {}
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 517ad07..d0f9eee 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -256,11 +256,11 @@
public static final int ERROR_UNSAFE_RESOURCE = -16;
/** @hide */
- @IntDef({
- SAFE_BROWSING_THREAT_UNKNOWN,
- SAFE_BROWSING_THREAT_MALWARE,
- SAFE_BROWSING_THREAT_PHISHING,
- SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE
+ @IntDef(prefix = { "SAFE_BROWSING_THREAT_" }, value = {
+ SAFE_BROWSING_THREAT_UNKNOWN,
+ SAFE_BROWSING_THREAT_MALWARE,
+ SAFE_BROWSING_THREAT_PHISHING,
+ SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE
})
@Retention(RetentionPolicy.SOURCE)
public @interface SafeBrowsingThreat {}
@@ -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/DatePicker.java b/core/java/android/widget/DatePicker.java
index dfb3642..b2b93fa 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -107,7 +107,10 @@
public static final int MODE_CALENDAR = 2;
/** @hide */
- @IntDef({MODE_SPINNER, MODE_CALENDAR})
+ @IntDef(prefix = { "MODE_" }, value = {
+ MODE_SPINNER,
+ MODE_CALENDAR
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface DatePickerMode {}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 05cba1e..a440398 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;
@@ -545,7 +544,8 @@
chooseSize(mErrorPopup, mError, tv);
tv.setText(mError);
- mErrorPopup.showAsDropDown(mTextView, getErrorX(), getErrorY());
+ mErrorPopup.showAsDropDown(mTextView, getErrorX(), getErrorY(),
+ Gravity.TOP | Gravity.LEFT);
mErrorPopup.fixDirection(mErrorPopup.isAboveAnchor());
}
@@ -3982,31 +3982,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 +4030,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 +4078,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;
@@ -4930,7 +4924,10 @@
}
@Retention(RetentionPolicy.SOURCE)
- @IntDef({HANDLE_TYPE_SELECTION_START, HANDLE_TYPE_SELECTION_END})
+ @IntDef(prefix = { "HANDLE_TYPE_" }, value = {
+ HANDLE_TYPE_SELECTION_START,
+ HANDLE_TYPE_SELECTION_END
+ })
public @interface HandleType {}
public static final int HANDLE_TYPE_SELECTION_START = 0;
public static final int HANDLE_TYPE_SELECTION_END = 1;
@@ -6135,7 +6132,11 @@
}
@Retention(RetentionPolicy.SOURCE)
- @IntDef({MERGE_EDIT_MODE_FORCE_MERGE, MERGE_EDIT_MODE_NEVER_MERGE, MERGE_EDIT_MODE_NORMAL})
+ @IntDef(prefix = { "MERGE_EDIT_MODE_" }, value = {
+ MERGE_EDIT_MODE_FORCE_MERGE,
+ MERGE_EDIT_MODE_NEVER_MERGE,
+ MERGE_EDIT_MODE_NORMAL
+ })
private @interface MergeMode {}
private static final int MERGE_EDIT_MODE_FORCE_MERGE = 0;
private static final int MERGE_EDIT_MODE_NEVER_MERGE = 1;
@@ -6594,7 +6595,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/GridLayout.java b/core/java/android/widget/GridLayout.java
index cbd1e0a..012b918 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -172,7 +172,10 @@
// Public constants
/** @hide */
- @IntDef({HORIZONTAL, VERTICAL})
+ @IntDef(prefix = { "HORIZONTAL", "VERTICAL" }, value = {
+ HORIZONTAL,
+ VERTICAL
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Orientation {}
@@ -198,7 +201,10 @@
public static final int UNDEFINED = Integer.MIN_VALUE;
/** @hide */
- @IntDef({ALIGN_BOUNDS, ALIGN_MARGINS})
+ @IntDef(prefix = { "ALIGN_" }, value = {
+ ALIGN_BOUNDS,
+ ALIGN_MARGINS
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface AlignmentMode {}
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index fcb44af..1ec9b2f 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -65,7 +65,12 @@
@RemoteView
public class GridView extends AbsListView {
/** @hide */
- @IntDef({NO_STRETCH, STRETCH_SPACING, STRETCH_COLUMN_WIDTH, STRETCH_SPACING_UNIFORM})
+ @IntDef(prefix = { "NO_STRETCH", "STRETCH_" }, value = {
+ NO_STRETCH,
+ STRETCH_SPACING,
+ STRETCH_COLUMN_WIDTH,
+ STRETCH_SPACING_UNIFORM
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface StretchMode {}
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 380bf7a..7ea1f1e 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -95,13 +95,12 @@
public static final int VERTICAL = 1;
/** @hide */
- @IntDef(flag = true,
- value = {
- SHOW_DIVIDER_NONE,
- SHOW_DIVIDER_BEGINNING,
- SHOW_DIVIDER_MIDDLE,
- SHOW_DIVIDER_END
- })
+ @IntDef(flag = true, prefix = { "SHOW_DIVIDER_" }, value = {
+ SHOW_DIVIDER_NONE,
+ SHOW_DIVIDER_BEGINNING,
+ SHOW_DIVIDER_MIDDLE,
+ SHOW_DIVIDER_END
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface DividerMode {}
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 4d3189e..d98b865 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -510,7 +510,11 @@
*/
public interface OnScrollListener {
/** @hide */
- @IntDef({SCROLL_STATE_IDLE, SCROLL_STATE_TOUCH_SCROLL, SCROLL_STATE_FLING})
+ @IntDef(prefix = { "SCROLL_STATE_" }, value = {
+ SCROLL_STATE_IDLE,
+ SCROLL_STATE_TOUCH_SCROLL,
+ SCROLL_STATE_FLING
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface ScrollState {}
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/TextView.java b/core/java/android/widget/TextView.java
index d9bc51f..903d3ca 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -77,6 +77,7 @@
import android.text.InputType;
import android.text.Layout;
import android.text.ParcelableSpan;
+import android.text.PremeasuredText;
import android.text.Selection;
import android.text.SpanWatcher;
import android.text.Spannable;
@@ -750,7 +751,10 @@
public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1;
/** @hide */
- @IntDef({AUTO_SIZE_TEXT_TYPE_NONE, AUTO_SIZE_TEXT_TYPE_UNIFORM})
+ @IntDef(prefix = { "AUTO_SIZE_TEXT_TYPE_" }, value = {
+ AUTO_SIZE_TEXT_TYPE_NONE,
+ AUTO_SIZE_TEXT_TYPE_UNIFORM
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface AutoSizeTextType {}
// Default minimum size for auto-sizing text in scaled pixels.
@@ -5326,7 +5330,7 @@
if (imm != null) imm.restartInput(this);
} else if (type == BufferType.SPANNABLE || mMovement != null) {
text = mSpannableFactory.newSpannable(text);
- } else if (!(text instanceof CharWrapper)) {
+ } else if (!(text instanceof PremeasuredText || text instanceof CharWrapper)) {
text = TextUtils.stringOrSpannedString(text);
}
@@ -5610,10 +5614,15 @@
spannable = (Spannable) text;
} else {
spannable = mSpannableFactory.newSpannable(text);
- text = spannable;
}
SuggestionSpan[] spans = spannable.getSpans(0, text.length(), SuggestionSpan.class);
+ if (spans.length == 0) {
+ return text;
+ } else {
+ text = spannable;
+ }
+
for (int i = 0; i < spans.length; i++) {
spannable.removeSpan(spans[i]);
}
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/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index ae6881e..cfec3f2 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -77,7 +77,10 @@
public static final int MODE_CLOCK = 2;
/** @hide */
- @IntDef({MODE_SPINNER, MODE_CLOCK})
+ @IntDef(prefix = { "MODE_" }, value = {
+ MODE_SPINNER,
+ MODE_CLOCK
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface TimePickerMode {}
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index d807120..edcf209 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -71,7 +71,10 @@
static final boolean localLOGV = false;
/** @hide */
- @IntDef({LENGTH_SHORT, LENGTH_LONG})
+ @IntDef(prefix = { "LENGTH_" }, value = {
+ LENGTH_SHORT,
+ LENGTH_LONG
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Duration {}
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/graphics/SfVsyncFrameCallbackProvider.java b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
index 931eb99..45555bf 100644
--- a/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
+++ b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
@@ -26,7 +26,15 @@
*/
public final class SfVsyncFrameCallbackProvider implements AnimationFrameCallbackProvider {
- private final Choreographer mChoreographer = Choreographer.getSfInstance();
+ private final Choreographer mChoreographer;
+
+ public SfVsyncFrameCallbackProvider() {
+ mChoreographer = Choreographer.getSfInstance();
+ }
+
+ public SfVsyncFrameCallbackProvider(Choreographer choreographer) {
+ mChoreographer = choreographer;
+ }
@Override
public void postFrameCallback(Choreographer.FrameCallback callback) {
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 3e231d0..d3b4dbf 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -16,6 +16,9 @@
package com.android.internal.inputmethod;
+import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR;
+import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_VIEW_HAS_FOCUS;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -26,6 +29,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.os.Build;
import android.os.LocaleList;
import android.os.RemoteException;
import android.provider.Settings;
@@ -33,6 +37,7 @@
import android.text.TextUtils.SimpleStringSplitter;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.util.Pair;
import android.util.Printer;
import android.util.Slog;
@@ -836,7 +841,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 +910,6 @@
mRes = res;
mResolver = resolver;
mMethodMap = methodMap;
- mMethodList = methodList;
switchCurrentUser(userId, copyOnWrite);
}
@@ -1087,7 +1090,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);
}
}
@@ -1512,4 +1515,20 @@
}
return locales;
}
+
+ public static boolean isSoftInputModeStateVisibleAllowed(
+ int targetSdkVersion, int controlFlags) {
+ if (targetSdkVersion < Build.VERSION_CODES.P) {
+ // for compatibility.
+ return true;
+ }
+ if ((controlFlags & CONTROL_WINDOW_VIEW_HAS_FOCUS) == 0) {
+ return false;
+ }
+ if ((controlFlags & CONTROL_WINDOW_IS_TEXT_EDITOR) == 0) {
+ return false;
+ }
+ return true;
+ }
+
}
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/net/OWNERS b/core/java/com/android/internal/net/OWNERS
index e2064a8..10d44bd 100644
--- a/core/java/com/android/internal/net/OWNERS
+++ b/core/java/com/android/internal/net/OWNERS
@@ -2,5 +2,7 @@
ek@google.com
hugobenichi@google.com
+jchalard@google.com
jsharkey@android.com
lorenzo@google.com
+satk@google.com
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 56d0bb2..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);
}
}
@@ -8928,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) {
@@ -8952,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);
@@ -9280,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");
@@ -9409,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")) {
@@ -12110,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 {
@@ -12535,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/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index e5d5716..91c76af 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -494,4 +494,38 @@
return value;
}
+
+ /**
+ * Ensures that all elements in the argument integer array are within the inclusive range
+ *
+ * @param value an integer array of values
+ * @param lower the lower endpoint of the inclusive range
+ * @param upper the upper endpoint of the inclusive range
+ * @param valueName the name of the argument to use if the check fails
+ *
+ * @return the validated integer array
+ *
+ * @throws IllegalArgumentException if any of the elements in {@code value} were out of range
+ * @throws NullPointerException if the {@code value} was {@code null}
+ */
+ public static int[] checkArrayElementsInRange(int[] value, int lower, int upper,
+ String valueName) {
+ checkNotNull(value, valueName + " must not be null");
+
+ for (int i = 0; i < value.length; ++i) {
+ int v = value[i];
+
+ if (v < lower) {
+ throw new IllegalArgumentException(
+ String.format("%s[%d] is out of range of [%d, %d] (too low)",
+ valueName, i, lower, upper));
+ } else if (v > upper) {
+ throw new IllegalArgumentException(
+ String.format("%s[%d] is out of range of [%d, %d] (too high)",
+ valueName, i, lower, upper));
+ }
+ }
+
+ return value;
+ }
}
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/services/core/java/com/android/server/timezone/ClockHelper.java b/core/java/com/android/internal/util/function/QuadConsumer.java
similarity index 74%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/java/com/android/internal/util/function/QuadConsumer.java
index 353728a..d899c01 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/java/com/android/internal/util/function/QuadConsumer.java
@@ -14,12 +14,16 @@
* limitations under the License.
*/
-package com.android.server.timezone;
+package com.android.internal.util.function;
+
+
+import java.util.function.Consumer;
/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
+ * A 4-argument {@link Consumer}
+ *
+ * @hide
*/
-interface ClockHelper {
-
- long currentTimestamp();
+public interface QuadConsumer<A, B, C, D> {
+ void accept(A a, B b, C c, D d);
}
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/core/java/com/android/internal/util/function/QuadFunction.java
similarity index 74%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/java/com/android/internal/util/function/QuadFunction.java
index 353728a..700d953 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/java/com/android/internal/util/function/QuadFunction.java
@@ -14,12 +14,16 @@
* limitations under the License.
*/
-package com.android.server.timezone;
+package com.android.internal.util.function;
+
+
+import java.util.function.Function;
/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
+ * A 4-argument {@link Function}
+ *
+ * @hide
*/
-interface ClockHelper {
-
- long currentTimestamp();
+public interface QuadFunction<A, B, C, D, R> {
+ R apply(A a, B b, C c, D d);
}
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/core/java/com/android/internal/util/function/QuadPredicate.java
similarity index 74%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/java/com/android/internal/util/function/QuadPredicate.java
index 353728a..512c98b 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/java/com/android/internal/util/function/QuadPredicate.java
@@ -14,12 +14,16 @@
* limitations under the License.
*/
-package com.android.server.timezone;
+package com.android.internal.util.function;
+
+
+import java.util.function.Predicate;
/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
+ * A 4-argument {@link Predicate}
+ *
+ * @hide
*/
-interface ClockHelper {
-
- long currentTimestamp();
+public interface QuadPredicate<A, B, C, D> {
+ boolean test(A a, B b, C c, D d);
}
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/core/java/com/android/internal/util/function/TriConsumer.java
similarity index 75%
rename from services/core/java/com/android/server/timezone/ClockHelper.java
rename to core/java/com/android/internal/util/function/TriConsumer.java
index 353728a..40d614e 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/java/com/android/internal/util/function/TriConsumer.java
@@ -14,12 +14,16 @@
* limitations under the License.
*/
-package com.android.server.timezone;
+package com.android.internal.util.function;
+
+
+import java.util.function.Consumer;
/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
+ * A 3-argument {@link Consumer}
+ *
+ * @hide
*/
-interface ClockHelper {
-
- long currentTimestamp();
+public interface TriConsumer<A, B, C> {
+ void accept(A a, B b, C c);
}
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/core/java/com/android/internal/util/function/TriFunction.java
similarity index 75%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/java/com/android/internal/util/function/TriFunction.java
index 353728a..2b1df86 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/java/com/android/internal/util/function/TriFunction.java
@@ -14,12 +14,16 @@
* limitations under the License.
*/
-package com.android.server.timezone;
+package com.android.internal.util.function;
+
+
+import java.util.function.Function;
/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
+ * A 3-argument {@link Function}
+ *
+ * @hide
*/
-interface ClockHelper {
-
- long currentTimestamp();
+public interface TriFunction<A, B, C, R> {
+ R apply(A a, B b, C c);
}
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/core/java/com/android/internal/util/function/TriPredicate.java
similarity index 75%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/java/com/android/internal/util/function/TriPredicate.java
index 353728a..d9cd968 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/java/com/android/internal/util/function/TriPredicate.java
@@ -14,12 +14,16 @@
* limitations under the License.
*/
-package com.android.server.timezone;
+package com.android.internal.util.function;
+
+
+import java.util.function.Predicate;
/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
+ * A 3-argument {@link Predicate}
+ *
+ * @hide
*/
-interface ClockHelper {
-
- long currentTimestamp();
+public interface TriPredicate<A, B, C> {
+ boolean test(A a, B b, C c);
}
diff --git a/tests/CantSaveState2/src/com/android/test/cantsavestate2/CantSave2Activity.java b/core/java/com/android/internal/util/function/pooled/ArgumentPlaceholder.java
similarity index 63%
copy from tests/CantSaveState2/src/com/android/test/cantsavestate2/CantSave2Activity.java
copy to core/java/com/android/internal/util/function/pooled/ArgumentPlaceholder.java
index 3ce63c7..cf86b71 100644
--- a/tests/CantSaveState2/src/com/android/test/cantsavestate2/CantSave2Activity.java
+++ b/core/java/com/android/internal/util/function/pooled/ArgumentPlaceholder.java
@@ -14,15 +14,20 @@
* limitations under the License.
*/
-package com.android.test.cantsavestate2;
+package com.android.internal.util.function.pooled;
-import android.app.Activity;
-import android.os.Bundle;
+/**
+ * A placeholder for an argument of type {@code R}
+ *
+ * @see PooledLambda
+ * @hide
+ */
+public final class ArgumentPlaceholder<R> {
+ private ArgumentPlaceholder() {}
+ static final ArgumentPlaceholder<?> INSTANCE = new ArgumentPlaceholder<>();
-public class CantSave2Activity extends Activity {
@Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.cant_save_2_activity);
+ 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/services/core/java/com/android/server/timezone/ClockHelper.java b/core/java/com/android/internal/util/function/pooled/PooledConsumer.java
similarity index 67%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/java/com/android/internal/util/function/pooled/PooledConsumer.java
index 353728a..f66586e 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledConsumer.java
@@ -14,12 +14,18 @@
* limitations under the License.
*/
-package com.android.server.timezone;
+package com.android.internal.util.function.pooled;
+
+import java.util.function.Consumer;
/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
+ * {@link Consumer} + {@link PooledLambda}
+ *
+ * @see PooledLambda
+ * @hide
*/
-interface ClockHelper {
+public interface PooledConsumer<T> extends PooledLambda, Consumer<T> {
- long currentTimestamp();
+ /** @inheritDoc */
+ PooledConsumer<T> recycleOnUse();
}
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/core/java/com/android/internal/util/function/pooled/PooledFunction.java
similarity index 61%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/java/com/android/internal/util/function/pooled/PooledFunction.java
index 353728a..1f166fa 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledFunction.java
@@ -14,12 +14,23 @@
* limitations under the License.
*/
-package com.android.server.timezone;
+package com.android.internal.util.function.pooled;
+
+import java.util.function.Function;
/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
+ * {@link Function} + {@link PooledLambda}
+ *
+ * @see PooledLambda
+ * @hide
*/
-interface ClockHelper {
+public interface PooledFunction<A, R> extends PooledLambda, Function<A, R> {
- long currentTimestamp();
+ /**
+ * 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%
rename from core/java/android/service/autofill/IAuthenticationCallback.aidl
rename 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/tests/CantSaveState2/src/com/android/test/cantsavestate2/CantSave2Activity.java b/core/java/com/android/internal/util/function/pooled/PooledRunnable.java
similarity index 64%
rename from tests/CantSaveState2/src/com/android/test/cantsavestate2/CantSave2Activity.java
rename to core/java/com/android/internal/util/function/pooled/PooledRunnable.java
index 3ce63c7..89ca82e 100644
--- a/tests/CantSaveState2/src/com/android/test/cantsavestate2/CantSave2Activity.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledRunnable.java
@@ -14,15 +14,17 @@
* limitations under the License.
*/
-package com.android.test.cantsavestate2;
+package com.android.internal.util.function.pooled;
-import android.app.Activity;
-import android.os.Bundle;
+import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
-public class CantSave2Activity extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.cant_save_2_activity);
- }
+/**
+ * {@link Runnable} + {@link PooledLambda}
+ *
+ * @see PooledLambda
+ * @hide
+ */
+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..ac03d74 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,
@@ -60,7 +61,8 @@
in IInputMethodClient client, in IBinder windowToken, int controlFlags,
/* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
int windowFlags, in EditorInfo attribute, IInputContext inputContext,
- /* @InputConnectionInspector.MissingMethodFlags */ int missingMethodFlags);
+ /* @InputConnectionInspector.MissingMethodFlags */ int missingMethodFlags,
+ int unverifiedTargetSdkVersion);
void showInputMethodPickerFromClient(in IInputMethodClient client,
int auxiliarySubtypeMode);
@@ -79,7 +81,6 @@
boolean switchToLastInputMethod(in IBinder token);
boolean switchToNextInputMethod(in IBinder token, boolean onlyCurrentIme);
boolean shouldOfferSwitchingToNextInputMethod(in IBinder token);
- boolean setInputMethodEnabled(String id, boolean enabled);
void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
int getInputMethodWindowVisibleHeight();
void clearLastInputMethodWindowForTransition(in IBinder token);
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/ButtonBarLayout.java b/core/java/com/android/internal/widget/ButtonBarLayout.java
index 6a0edef..82affe2 100644
--- a/core/java/com/android/internal/widget/ButtonBarLayout.java
+++ b/core/java/com/android/internal/widget/ButtonBarLayout.java
@@ -151,7 +151,7 @@
private void setStacked(boolean stacked) {
setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
- setGravity(stacked ? Gravity.RIGHT : Gravity.BOTTOM);
+ setGravity(stacked ? Gravity.END : Gravity.BOTTOM);
final View spacer = findViewById(R.id.spacer);
if (spacer != null) {
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/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index 4354486..8848e393 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -33,6 +33,7 @@
import android.provider.Downloads;
import android.text.TextUtils;
import android.util.AtomicFile;
+import android.util.EventLog;
import android.util.Slog;
import android.util.Xml;
@@ -40,6 +41,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.server.DropboxLogTags;
import java.io.File;
import java.io.FileInputStream;
@@ -297,6 +299,7 @@
Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")");
db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n") +
footers);
+ EventLog.writeEvent(DropboxLogTags.DROPBOX_FILE_COPY, filename, maxSize, tag);
}
private static void addAuditErrorsToDropBox(DropBoxManager db,
diff --git a/core/java/com/android/server/DropboxLogTags.logtags b/core/java/com/android/server/DropboxLogTags.logtags
new file mode 100644
index 0000000..c461cfe
--- /dev/null
+++ b/core/java/com/android/server/DropboxLogTags.logtags
@@ -0,0 +1,12 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+# The java package name happens to be the same as frameworks/base/services/core
+# /java/com/android/server/EventLogTags.logtags. To avoid conflict, this file's name cannot
+# be EventLogTags.logtags because it generates a class with the same name.
+
+option java_package com.android.server;
+
+# -----------------------------
+# BootReceiver.java
+# -----------------------------
+81002 dropbox_file_copy (FileName|3),(Size|1),(Tag|3)
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/java/com/android/server/net/OWNERS b/core/java/com/android/server/net/OWNERS
index 74f39a1..6f77e04 100644
--- a/core/java/com/android/server/net/OWNERS
+++ b/core/java/com/android/server/net/OWNERS
@@ -2,4 +2,6 @@
ek@google.com
hugobenichi@google.com
+jchalard@google.com
lorenzo@google.com
+satk@google.com
diff --git a/core/java/org/chromium/arc/EventLogTags.logtags b/core/java/org/chromium/arc/EventLogTags.logtags
new file mode 100644
index 0000000..1b7160e
--- /dev/null
+++ b/core/java/org/chromium/arc/EventLogTags.logtags
@@ -0,0 +1,11 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package org.chromium.arc
+
+# We use ID range 300000-399999 for ARC.
+# In case of conflicts build will fail, so we do not need to worry too much
+# about it.
+
+# Emitted in ARC system events, such as start of ARC services.
+# These events will be watched in automations like autotests.
+300000 arc_system_event (event|3)
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/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index 460a0d7..564afeb 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -101,7 +101,8 @@
SkIRect src = SkIRect::MakeWH(bitmap.width(), bitmap.height());
lattice.fBounds = &src;
NinePatchUtils::SetLatticeDivs(&lattice, *chunk, bitmap.width(), bitmap.height());
- lattice.fFlags = nullptr;
+ lattice.fRectTypes = nullptr;
+ lattice.fColors = nullptr;
SkRegion* region = nullptr;
if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), lattice)) {
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_Debug.cpp b/core/jni/android_os_Debug.cpp
index d3da21b..b9ff0a7 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -747,7 +747,7 @@
static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)
{
- char buffer[1024];
+ char buffer[4096];
size_t numFound = 0;
if (out == NULL) {
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_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 8c968a2..5e5d59b 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -868,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",
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/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/app/activitymanager.proto b/core/proto/android/app/activitymanager.proto
index e87499e..7385050 100644
--- a/core/proto/android/app/activitymanager.proto
+++ b/core/proto/android/app/activitymanager.proto
@@ -20,61 +20,59 @@
option java_multiple_files = true;
-message ActivityManagerProto {
+// ActivityManager.java PROCESS_STATEs
+enum ProcessState {
+ // Order matters for process states, so values have been spaced to provide
+ // room for future additions.
- // ActivityManager.java PROCESS_STATEs
- enum ProcessState {
- // Order matters for process states, so values have been spaced to provide
- // room for future additions.
-
- // Not a real process state.
- PROCESS_STATE_UNKNOWN = -100;
- // Process is a persistent system process.
- PROCESS_STATE_PERSISTENT = 0;
- // Process is a persistent system process and is doing UI.
- PROCESS_STATE_PERSISTENT_UI = 100;
- // Process is hosting the current top activities. Note that this covers
- // all activities that are visible to the user.
- PROCESS_STATE_TOP = 200;
- // Process is hosting a foreground service due to a system binding.
- PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 300;
- // Process is hosting a foreground service.
- PROCESS_STATE_FOREGROUND_SERVICE = 400;
- // Same as PROCESS_STATE_TOP but while device is sleeping.
- PROCESS_STATE_TOP_SLEEPING = 500;
- // Process is important to the user, and something they are aware of.
- PROCESS_STATE_IMPORTANT_FOREGROUND = 600;
- // Process is important to the user, but not something they are aware of.
- PROCESS_STATE_IMPORTANT_BACKGROUND = 700;
- // Process is in the background transient so we will try to keep running.
- PROCESS_STATE_TRANSIENT_BACKGROUND = 800;
- // Process is in the background running a backup/restore operation.
- PROCESS_STATE_BACKUP = 900;
- // Process is in the background, but it can't restore its state so we want
- // to try to avoid killing it.
- PROCESS_STATE_HEAVY_WEIGHT = 1000;
- // Process is in the background running a service. Unlike oom_adj, this
- // level is used for both the normal running in background state and the
- // executing operations state.
- PROCESS_STATE_SERVICE = 1100;
- // Process is in the background running a receiver. Note that from the
- // perspective of oom_adj, receivers run at a higher foreground level, but
- // for our prioritization here that is not necessary and putting them
- // below services means many fewer changes in some process states as they
- // receive broadcasts.
- PROCESS_STATE_RECEIVER = 1200;
- // Process is in the background but hosts the home activity.
- PROCESS_STATE_HOME = 1300;
- // Process is in the background but hosts the last shown activity.
- PROCESS_STATE_LAST_ACTIVITY = 1400;
- // Process is being cached for later use and contains activities.
- PROCESS_STATE_CACHED_ACTIVITY = 1500;
- // Process is being cached for later use and is a client of another cached
- // process that contains activities.
- PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 1600;
- // Process is being cached for later use and is empty.
- PROCESS_STATE_CACHED_EMPTY = 1700;
- // Process does not exist.
- PROCESS_STATE_NONEXISTENT = 1800;
- }
+ // Not a real process state.
+ PROCESS_STATE_UNKNOWN = -100;
+ // Process is a persistent system process.
+ PROCESS_STATE_PERSISTENT = 0;
+ // Process is a persistent system process and is doing UI.
+ PROCESS_STATE_PERSISTENT_UI = 100;
+ // Process is hosting the current top activities. Note that this covers
+ // all activities that are visible to the user.
+ PROCESS_STATE_TOP = 200;
+ // Process is hosting a foreground service due to a system binding.
+ PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 300;
+ // Process is hosting a foreground service.
+ PROCESS_STATE_FOREGROUND_SERVICE = 400;
+ // Same as PROCESS_STATE_TOP but while device is sleeping.
+ PROCESS_STATE_TOP_SLEEPING = 500;
+ // Process is important to the user, and something they are aware of.
+ PROCESS_STATE_IMPORTANT_FOREGROUND = 600;
+ // Process is important to the user, but not something they are aware of.
+ PROCESS_STATE_IMPORTANT_BACKGROUND = 700;
+ // Process is in the background transient so we will try to keep running.
+ PROCESS_STATE_TRANSIENT_BACKGROUND = 800;
+ // Process is in the background running a backup/restore operation.
+ PROCESS_STATE_BACKUP = 900;
+ // Process is in the background, but it can't restore its state so we want
+ // to try to avoid killing it.
+ PROCESS_STATE_HEAVY_WEIGHT = 1000;
+ // Process is in the background running a service. Unlike oom_adj, this
+ // level is used for both the normal running in background state and the
+ // executing operations state.
+ PROCESS_STATE_SERVICE = 1100;
+ // Process is in the background running a receiver. Note that from the
+ // perspective of oom_adj, receivers run at a higher foreground level, but
+ // for our prioritization here that is not necessary and putting them
+ // below services means many fewer changes in some process states as they
+ // receive broadcasts.
+ PROCESS_STATE_RECEIVER = 1200;
+ // Process is in the background but hosts the home activity.
+ PROCESS_STATE_HOME = 1300;
+ // Process is in the background but hosts the last shown activity.
+ PROCESS_STATE_LAST_ACTIVITY = 1400;
+ // Process is being cached for later use and contains activities.
+ PROCESS_STATE_CACHED_ACTIVITY = 1500;
+ // Process is being cached for later use and is a client of another cached
+ // process that contains activities.
+ PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 1600;
+ // Process is being cached for later use and is empty.
+ PROCESS_STATE_CACHED_EMPTY = 1700;
+ // Process does not exist.
+ PROCESS_STATE_NONEXISTENT = 1800;
}
+
diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto
index cff1879..0fa428e 100644
--- a/core/proto/android/os/batterystats.proto
+++ b/core/proto/android/os/batterystats.proto
@@ -28,12 +28,8 @@
optional int64 parcel_version = 2;
optional string start_platform_version = 3;
optional string end_platform_version = 4;
- optional BatteryHistoryProto history = 5;
- repeated UidProto uids = 6;
- optional SystemProto system = 7;
-}
-
-message BatteryHistoryProto {
+ repeated UidProto uids = 5;
+ optional SystemProto system = 6;
}
message ControllerActivityProto {
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index ecdabcf..4015a7e 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,15 +40,26 @@
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;
+// This field contains internal metadata associated with an incident report,
+// such as the section ids and privacy policy specs from caller as well as how long
+// and how many bytes a section takes, etc.
+message IncidentMetadata {
+
+}
+
// privacy field options must not be set at this level because all
// the sections are able to be controlled and configured by section ids.
// Instead privacy field options need to be configured in each section proto message.
message IncidentProto {
- // Incident header
+ // Incident header from callers
repeated IncidentHeaderProto header = 1;
+ // Internal metadata of incidentd
+ optional IncidentMetadata metadata = 2;
// Device information
optional SystemPropertiesProto system_properties = 1000 [
@@ -164,4 +173,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/incidentheader.proto b/core/proto/android/os/incidentheader.proto
index ce924da..f0c736a 100644
--- a/core/proto/android/os/incidentheader.proto
+++ b/core/proto/android/os/incidentheader.proto
@@ -16,18 +16,34 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "IncidentHeaderProtoMetadata";
package android.os;
+// IncidentHeaderProto contains extra information the caller of incidentd want to
+// attach in an incident report, the data should just be informative.
message IncidentHeaderProto {
- enum Cause {
- CAUSE_UNKNOWN = 0;
- CAUSE_USER = 1;
- CAUSE_ANR = 2;
- CAUSE_CRASH = 3;
+
+ // From statsd config, the name of the anomaly, usually human readable.
+ optional string incident_name = 1;
+
+ // Format a human readable reason why an incident report is requested.
+ // It's optional and may directly come from a user clicking the bug-report button.
+ optional string reason = 2;
+
+ // From statsd, the metric which causes the anomaly triggered.
+ optional string metric_name = 3;
+
+ // From statsd, the metric value exceeds the threshold. This is useful for
+ // ValueMetric and GaugeMetric.
+ oneof metric_value {
+ int64 int64_value = 4;
+ double double_value = 5;
}
- optional Cause cause = 1;
+ // Defines which stats config used to fire the request.
+ message StatsdConfigKey {
+ optional int32 uid = 1;
+ optional string name = 2;
+ }
+ optional StatsdConfigKey config_key = 6;
}
-
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/os/system_properties.proto b/core/proto/android/os/system_properties.proto
index 921bb5a..76a108b 100644
--- a/core/proto/android/os/system_properties.proto
+++ b/core/proto/android/os/system_properties.proto
@@ -17,641 +17,456 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "SystemPropertiesProtoMetadata";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
import "frameworks/base/tools/streaming_proto/stream.proto";
package android.os;
-// System Properties from getprop
+// Android Platform Exported System Properties
+// TODO: This is not the completed list, new properties need to be whitelisted.
message SystemPropertiesProto {
- option (stream_proto.stream_msg).enable_fields_mapping = true;
+ option (stream_proto.stream_msg).enable_fields_mapping_recursively = true;
- // Properties that are not specified below are appended here.
+ // Properties that are not specified below would be appended here.
+ // These values stay on device only.
message Property {
+ option (android.msg_privacy).dest = DEST_LOCAL;
+
optional string name = 1;
optional string value = 2;
}
repeated Property extra_properties = 1;
- optional int32 aaudio_hw_burst_min_usec = 2;
- optional int32 aaudio_mmap_exclusive_policy = 3;
- optional int32 aaudio_mmap_policy = 4;
-
- optional int32 af_fast_track_multiplier = 5;
-
- optional int32 audio_adm_buffering_ms = 6;
- optional int32 audio_hal_period_size = 7;
-
- optional string dalvik_vm_appimageformat = 8;
- optional string dalvik_vm_dex2oat_Xms = 9;
- optional string dalvik_vm_dex2oat_Xmx = 10;
- optional bool dalvik_vm_dexopt_secondary = 11;
- optional string dalvik_vm_heapgrowthlimit = 12;
- optional string dalvik_vm_heapmaxfree = 13;
- optional string dalvik_vm_heapminfree = 14;
- optional string dalvik_vm_heapsize = 15;
- optional string dalvik_vm_heapstartsize = 16;
- optional float dalvik_vm_heaptargetutilization = 17;
- optional string dalvik_vm_image_dex2oat_Xms = 18;
- optional string dalvik_vm_image_dex2oat_Xmx = 19;
- optional string dalvik_vm_image_dex2oat_filter = 20;
- optional string dalvik_vm_isa_arm_features = 21;
- optional string dalvik_vm_isa_arm_variant = 22;
- optional string dalvik_vm_isa_arm64_features = 23;
- optional string dalvik_vm_isa_arm64_variant = 24;
- optional int32 dalvik_vm_lockprof_threshold = 25;
- optional string dalvik_vm_stack_trace_dir = 26;
- optional bool dalvik_vm_usejit = 27;
- optional bool dalvik_vm_usejitprofiles = 28;
-
- optional int32 debug_atrace_tags_enableflags = 29;
- optional int32 debug_force_rtl = 30;
- optional string debug_htc_hrdump = 31;
-
- optional int32 dev_bootcomplete = 32;
-
- optional bool drm_service_enabled = 33;
-
- optional int32 fmas_hdph_sgain = 34;
-
- optional int32 gsm_current_phone_type = 35;
- optional string gsm_network_type = 36;
- optional string gsm_operator_alpha = 37;
- optional string gsm_operator_iso_country = 38;
- optional bool gsm_operator_isroaming = 39;
- optional string gsm_operator_numeric = 40;
- optional string gsm_sim_operator_alpha = 41;
- optional string gsm_sim_operator_iso_country = 42;
- optional int32 gsm_sim_operator_numeric = 43;
- optional string gsm_sim_state = 44;
- optional string gsm_version_baseband = 45;
- optional string gsm_version_ril_impl = 46;
-
- optional sint32 htc_camera_sensor_inf = 47;
-
- optional bool hwservicemanager_ready = 48;
-
- // Enum values for a lot of system properties
- enum Status {
- STATUS_UNKNOWN = 0;
- STATUS_RUNNING = 1;
- STATUS_STOPPED = 2;
+ message AacDrc {
+ optional int32 boost = 1;
+ optional int32 cut = 2;
+ optional int32 enc_target_level = 3;
+ optional int32 heavy = 4;
+ optional int32 reference_level = 5;
}
- optional Status init_svc_adbd = 49;
- optional Status init_svc_audioserver = 50;
- optional Status init_svc_bootanim = 51;
- optional Status init_svc_bufferhubd = 52;
- optional Status init_svc_cameraserver = 53;
- optional Status init_svc_clear_bcb = 54;
- optional Status init_svc_drm = 55;
- optional Status init_svc_gatekeeperd = 56;
- optional Status init_svc_healthd = 57;
- optional Status init_svc_hidl_memory = 58;
- optional Status init_svc_hostapd = 59;
- optional Status init_svc_hwservicemanager = 60;
- optional Status init_svc_installd = 61;
- optional Status init_svc_keystore = 62;
- optional Status init_svc_lmkd = 63;
- optional Status init_svc_logd = 64;
- optional Status init_svc_logd_reinit = 65;
- optional Status init_svc_media = 66;
- optional Status init_svc_mediadrm = 67;
- optional Status init_svc_mediaextractor = 68;
- optional Status init_svc_mediametrics = 69;
- optional Status init_svc_netd = 70;
- optional Status init_svc_performanced = 71;
- optional Status init_svc_ril_daemon = 72;
- optional Status init_svc_servicemanager = 73;
- optional Status init_svc_storaged = 74;
- optional Status init_svc_surfaceflinger = 75;
- optional Status init_svc_thermalservice = 76;
- optional Status init_svc_tombstoned = 77;
- optional Status init_svc_ueventd = 78;
- optional Status init_svc_update_engine = 79;
- optional Status init_svc_update_verifier_nonencrypted = 80;
- optional Status init_svc_vendor_adsprpcd = 81;
- optional Status init_svc_vendor_atfwd = 82;
- optional Status init_svc_vendor_audio_hal_2_0 = 83;
- optional Status init_svc_vendor_bluetooth_1_0 = 84;
- optional Status init_svc_vendor_boot_hal_1_0 = 85;
- optional Status init_svc_vendor_camera_provider_2_4 = 86;
- optional Status init_svc_vendor_cas_hal_1_0 = 87;
- optional Status init_svc_vendor_cnd = 88;
- optional Status init_svc_vendor_cnss_daemon = 89;
- optional Status init_svc_vendor_cnss_diag = 90;
- optional Status init_svc_vendor_configstore_hal = 91;
- optional Status init_svc_vendor_contexthub_hal_1_0 = 92;
- optional Status init_svc_vendor_devstart_sh = 93;
- optional Status init_svc_vendor_drm_hal_1_0 = 94;
- optional Status init_svc_vendor_drm_widevine_hal_1_0 = 95;
- optional Status init_svc_vendor_dumpstate_1_0 = 96;
- optional Status init_svc_vendor_flash_nanohub_fw = 97;
- optional Status init_svc_vendor_foreground_sh = 98;
- optional Status init_svc_vendor_fps_hal = 99;
- optional Status init_svc_vendor_gatekeeper_1_0 = 100;
- optional Status init_svc_vendor_gnss_service = 101;
- optional Status init_svc_vendor_gralloc_2_0 = 102;
- optional Status init_svc_vendor_hci_filter_root = 103;
- optional Status init_svc_vendor_hwcomposer_2_1 = 104;
- optional Status init_svc_vendor_imsdatadaemon = 105;
- optional Status init_svc_vendor_imsqmidaemon = 106;
- optional Status init_svc_vendor_init_radio_sh = 107;
- optional Status init_svc_vendor_irsc_util = 108;
- optional Status init_svc_vendor_keymaster_3_0 = 109;
- optional Status init_svc_vendor_light_hal_2_0 = 110;
- optional Status init_svc_vendor_loc_launcher = 111;
- optional Status init_svc_vendor_media_omx = 112;
- optional Status init_svc_vendor_memtrack_hal_1_0 = 113;
- optional Status init_svc_vendor_mid_sh = 114;
- optional Status init_svc_vendor_msm_irqbalance = 115;
- optional Status init_svc_vendor_nanohub_slpi = 116;
- optional Status init_svc_vendor_netmgrd = 117;
- optional Status init_svc_vendor_nfc_hal_service = 118;
- optional Status init_svc_vendor_per_mgr = 119;
- optional Status init_svc_vendor_per_proxy = 120;
- optional Status init_svc_vendor_perfd = 121;
- optional Status init_svc_vendor_port_bridge = 122;
- optional Status init_svc_vendor_power_hal_1_1 = 123;
- optional Status init_svc_vendor_power_sh = 124;
- optional Status init_svc_vendor_qseecomd = 125;
- optional Status init_svc_vendor_ramdump_auto = 126;
- optional Status init_svc_vendor_rmt_storage = 127;
- optional Status init_svc_vendor_sensors_hal_1_0 = 128;
- optional Status init_svc_vendor_ss_ramdump = 129;
- optional Status init_svc_vendor_ssr_setup = 130;
- optional Status init_svc_vendor_thermal_engine = 131;
- optional Status init_svc_vendor_time_daemon = 132;
- optional Status init_svc_vendor_usb_hal_1_1 = 133;
- optional Status init_svc_vendor_vibrator_1_0 = 134;
- optional Status init_svc_vendor_vr_1_0 = 135;
- optional Status init_svc_vendor_wifi_hal_legacy = 136;
- optional Status init_svc_virtual_touchpad = 137;
- optional Status init_svc_vndservicemanager = 138;
- optional Status init_svc_vold = 139;
- optional Status init_svc_vr_hwc = 140;
- optional Status init_svc_webview_zygote32 = 141;
- optional Status init_svc_wificond = 142;
- optional Status init_svc_wpa_supplicant = 143;
- optional Status init_svc_zygote = 144;
- optional Status init_svc_zygote_secondary = 145;
+ optional AacDrc aac_drc = 2;
- optional bool keyguard_no_require_sim = 146;
+ message Aaudio {
+ optional int32 hw_burst_min_usec = 1;
+ optional int32 minimum_sleep_usec = 2;
+ optional int32 mixer_bursts = 3;
+ optional int32 mmap_exclusive_policy = 4;
+ optional int32 mmap_policy = 5;
+ optional int32 wakeup_delay_usec = 6;
- optional string log_tag_WifiHAL = 147;
+ // Next Tag: 7
+ }
+ optional Aaudio aaudio = 3;
- optional bool logd_logpersistd_enable = 148;
+ optional int32 af_fast_track_multiplier = 4;
- optional bool media_mediadrmservice_enable = 149;
- optional bool media_recorder_show_manufacturer_and_model = 150;
+ message Camera {
+ optional bool disable_zsl_mode = 1;
+ optional int32 fifo_disable = 2;
- optional string net_bt_name = 151;
- optional string net_dns1 = 152;
- optional string net_dns2 = 153;
- optional string net_dns3 = 154;
- optional string net_dns4 = 155;
- optional bool net_lte_ims_data_enabled = 156;
- optional int32 net_qtaguid_enabled = 157;
- optional int32 net_tcp_2g_init_rwnd = 158;
- repeated int32 net_tcp_buffersize_default = 159;
- repeated int32 net_tcp_buffersize_edge = 160;
- repeated int32 net_tcp_buffersize_evdo = 161;
- repeated int32 net_tcp_buffersize_gprs = 162;
- repeated int32 net_tcp_buffersize_hsdpa = 163;
- repeated int32 net_tcp_buffersize_hspa = 164;
- repeated int32 net_tcp_buffersize_hspap = 165;
- repeated int32 net_tcp_buffersize_hsupa = 166;
- repeated int32 net_tcp_buffersize_lte = 167;
- repeated int32 net_tcp_buffersize_umts = 168;
- repeated int32 net_tcp_buffersize_wifi = 169;
- optional int32 net_tcp_default_init_rwnd = 170;
+ // Next Tag: 3
+ }
+ optional Camera camera = 5;
- optional bool nfc_initialized = 171;
+ message DalvikVm {
+ optional string appimageformat = 1;
+ optional string backgroundgctype = 2;
+ optional bool checkjni = 3;
+ optional string dex2oat_filter = 4;
+ optional string dex2oat_flags = 5;
+ optional int32 dex2oat_threads = 6;
+ optional string dex2oat_Xms = 7;
+ optional string dex2oat_Xmx = 8;
+ optional bool dexopt_secondary = 9;
+ optional string execution_mode = 10;
+ optional string extra_opts = 11;
+ optional string gctype = 12;
+ optional string heapgrowthlimit = 13;
+ optional string heapmaxfree = 14;
+ optional string heapminfree = 15;
+ optional string heapsize = 16;
+ optional string heapstartsize = 17;
+ optional double heaptargetutilization = 18;
+ optional int32 hot_startup_method_samples = 19;
+ optional string image_dex2oat_filter = 20;
+ optional string image_dex2oat_flags = 21;
+ optional int32 image_dex2oat_threads = 22;
+ optional string image_dex2oat_Xms = 23;
+ optional string image_dex2oat_Xmx = 24;
+ optional string isa_arm_features = 25;
+ optional string isa_arm_variant = 26;
+ optional string isa_arm64_features = 27;
+ optional string isa_arm64_variant = 28;
+ optional string isa_mips_features = 29;
+ optional string isa_mips_variant = 30;
+ optional string isa_mips64_features = 31;
+ optional string isa_mips64_variant = 32;
+ optional string isa_unknown_features = 33;
+ optional string isa_unknown_variant = 34;
+ optional string isa_x86_64_features = 35;
+ optional string isa_x86_64_variant = 36;
+ optional string isa_x86_features = 37;
+ optional string isa_x86_variant = 38;
+ optional string jitinitialsize = 39;
+ optional string jitmaxsize = 40;
+ optional int32 jitprithreadweight = 41;
+ optional int32 jitthreshold = 42;
+ optional int32 jittransitionweight = 43;
+ optional string jniopts = 44;
+ optional int32 lockprof_threshold = 45;
+ optional bool method_trace = 46;
+ optional string method_trace_file = 47;
+ optional int32 method_trace_file_siz = 48;
+ optional bool method_trace_stream = 49;
+ optional bool profilesystemserver = 50;
+ optional string stack_trace_dir = 51;
+ optional bool usejit = 52;
+ optional bool usejitprofiles = 53;
+ optional int32 zygote_max_boot_retry = 54;
- optional bool persist_audio_fluence_speaker = 172;
- optional bool persist_audio_fluence_voicecall = 173;
- optional bool persist_audio_fluence_voicecomm = 174;
- optional bool persist_audio_fluence_voicerec = 175;
+ // Next Tag: 55
+ }
+ optional DalvikVm dalvik_vm = 6;
- optional int32 persist_camera_debug_logfile = 176;
- optional int32 persist_camera_eis_enable = 177;
- optional int32 persist_camera_gyro_android = 178;
- optional int32 persist_camera_is_type = 179;
- optional int32 persist_camera_tnr_preview = 180;
- optional int32 persist_camera_tnr_video = 181;
- optional int32 persist_camera_tof_direct = 182;
+ optional bool drm_64bit_enabled = 7;
+ optional bool drm_service_enabled = 8;
+ optional bool dumpstate_dry_run = 9;
+ optional string gsm_sim_operator_numeric = 10;
+ optional bool hal_instrumentation_enable = 11;
- optional int32 persist_cne_feature = 183;
+ message InitSvc {
+ enum Status {
+ STATUS_UNKNOWN = 0;
+ STATUS_RUNNING = 1;
+ STATUS_STOPPED = 2;
+ }
+ optional Status adbd = 1;
+ optional Status audioserver = 2;
+ optional Status bootanim = 3;
+ optional Status bufferhubd = 4;
+ optional Status cameraserver = 5;
+ optional Status clear_bcb = 6;
+ optional Status drm = 7;
+ optional Status gatekeeperd = 8;
+ optional Status healthd = 9;
+ optional Status hidl_memory = 10;
+ optional Status hostapd = 11;
+ optional Status hwservicemanager = 12;
+ optional Status installd = 13;
+ optional Status keystore = 14;
+ optional Status lmkd = 15;
+ optional Status logd = 16;
+ optional Status logd_reinit = 17;
+ optional Status media = 18;
+ optional Status mediadrm = 19;
+ optional Status mediaextractor = 20;
+ optional Status mediametrics = 21;
+ optional Status netd = 22;
+ optional Status performanced = 23;
+ optional Status ril_daemon = 24;
+ optional Status servicemanager = 25;
+ optional Status storaged = 26;
+ optional Status surfaceflinger = 27;
+ optional Status thermalservice = 28;
+ optional Status tombstoned = 29;
+ optional Status ueventd = 30;
+ optional Status update_engine = 31;
+ optional Status update_verifier_nonencrypted = 32;
+ optional Status virtual_touchpad = 33;
+ optional Status vndservicemanager = 34;
+ optional Status vold = 35;
+ optional Status vr_hwc = 36;
+ optional Status webview_zygote32 = 37;
+ optional Status wificond = 38;
+ optional Status wpa_supplicant = 39;
+ optional Status zygote = 40;
+ optional Status zygote_secondary = 41;
- optional bool persist_data_iwlan_enable = 184;
- optional string persist_data_mode = 185;
+ // Next Tag: 42
+ }
+ optional InitSvc init_svc = 12;
- optional int32 persist_radio_RATE_ADAPT_ENABLE = 186;
- optional int32 persist_radio_ROTATION_ENABLE = 187;
- optional int32 persist_radio_VT_ENABLE = 188;
- optional int32 persist_radio_VT_HYBRID_ENABLE = 189;
- optional int32 persist_radio_adb_log_on = 190;
- optional int32 persist_radio_airplane_mode_on = 191;
- optional int32 persist_radio_apm_sim_not_pwdn = 192;
- optional int32 persist_radio_custom_ecc = 193;
- optional bool persist_radio_data_con_rprt = 194;
- optional int32 persist_radio_data_ltd_sys_ind = 195;
- optional string persist_radio_enable_tel_mon = 196;
- optional bool persist_radio_eons_enabled = 197;
- optional bool persist_radio_is_wps_enabled = 198;
- optional int32 persist_radio_pwropt_modepref_0 = 199;
- optional int32 persist_radio_ril_payload_on = 200;
- optional int32 persist_radio_sglte_target = 201;
- optional int32 persist_radio_sib16_support = 202;
- optional int32 persist_radio_smlog_switch = 203;
- optional int32 persist_radio_snapshot_enabled = 204;
- optional int32 persist_radio_snapshot_timer = 205;
- optional int32 persist_radio_sw_mbn_loaded = 206;
- optional int32 persist_radio_sw_mbn_update = 207;
- optional string persist_radio_ver_info = 208;
- optional int32 persist_radio_videopause_mode = 209;
+ optional bool keyguard_no_require_sim = 13;
+ optional string libc_debug_malloc_options = 14;
+ optional string libc_debug_malloc_program = 15;
- optional int32 persist_rcs_supported = 210;
+ message Log {
+ optional string tag_WifiHAL = 1;
+ optional string tag_stats_log = 2;
- optional string persist_sys_boot_reason = 211;
- optional int32 persist_sys_cnd_iwlan = 212;
- optional string persist_sys_dalvik_vm_lib_2 = 213;
- optional string persist_sys_gps_lpp = 214;
- optional string persist_sys_locale = 215;
- optional int32 persist_sys_ssr_enable_ramdumps = 216;
- optional string persist_sys_ssr_restart_level = 217;
- optional string persist_sys_timezone = 218;
- optional string persist_sys_usb_config = 219;
- optional int32 persist_sys_webview_vmsize = 220;
+ // Next Tag: 3
+ }
+ optional Log log = 16;
- optional string pm_dexopt_ab_ota = 221;
- optional string pm_dexopt_bg_dexopt = 222;
- optional string pm_dexopt_boot = 223;
- optional string pm_dexopt_first_boot = 224;
- optional string pm_dexopt_inactive = 225;
- optional string pm_dexopt_install = 226;
- optional string pm_dexopt_shared = 227;
+ optional bool media_mediadrmservice_enable = 17;
+ optional bool media_recorder_show_manufacturer_and_model = 18;
- optional string qcom_bluetooth_soc = 228;
+ message Persist {
+ optional string config_calibration_fac = 1;
+ optional int32 dbg_volte_avail_ovr = 2;
+ optional int32 dbg_vt_avail_ovr = 3;
+ optional int32 dbg_wfc_avail_ovr = 4;
+ optional int32 radio_airplane_mode_on = 5;
+ optional string radio_multisim_config = 6;
+ optional int32 rcs_supported = 7;
+ optional bool sys_crash_rcu = 8;
+ optional string sys_dalvik_vm_lib_2 = 9;
+ optional float sys_sf_color_saturation = 10;
+ optional string sys_timezone = 11;
- optional int32 qdcm_diagonal_matrix_mode = 229;
- optional int32 qdcm_only_pcc_for_trans = 230;
+ // Next Tag: 12
+ }
+ optional Persist persist = 19;
- repeated string ril_ecclist = 231;
- optional int32 ril_power_backoff_suppressed = 232;
- optional int32 ril_qcril_pre_init_lock_held = 233;
- optional string ril_voice_network_type = 234;
- optional string rild_libpath = 235;
+ message PmDexopt {
+ optional string ab_ota = 1;
+ optional string bg_dexopt = 2;
+ optional string boot = 3;
+ optional string first_boot = 4;
+ optional string install = 5;
- optional int32 ro_adb_secure = 236;
- optional int32 ro_allow_mock_location = 237;
- repeated string ro_atrace_core_services = 238;
- optional string ro_baseband = 239;
- optional int32 ro_bionic_ld_warning = 240;
- optional bool ro_bluetooth_dun = 241;
- optional string ro_bluetooth_hfp_ver = 242;
- optional bool ro_bluetooth_sap = 243;
- optional string ro_board_platform = 244;
+ // Next Tag: 6
+ }
+ optional PmDexopt pm_dexopt = 20;
- optional string ro_boot_baseband = 245;
- optional string ro_boot_bootdevice = 246;
- optional string ro_boot_bootloader = 247;
- optional string ro_boot_bootreason = 248;
- repeated string ro_boot_boottime = 249;
- optional int32 ro_boot_cid = 250;
- optional string ro_boot_console = 251;
- optional string ro_boot_ddrinfo = 252;
- optional string ro_boot_ddrsize = 253;
- optional int32 ro_boot_flash_locked = 254;
- optional int32 ro_boot_fp_src = 255;
- optional string ro_boot_hardware = 256;
- optional string ro_boot_hardware_color = 257;
- optional string ro_boot_hardware_ddr = 258;
- optional string ro_boot_hardware_revision = 259;
- optional string ro_boot_hardware_sku = 260;
- optional string ro_boot_hardware_ufs = 261;
- optional string ro_boot_htc_hrdump = 262;
- optional int32 ro_boot_keymaster = 263;
- optional string ro_boot_mid = 264;
- optional int32 ro_boot_msm_hw_ver_id = 265;
- optional int32 ro_boot_oem_unlock_support = 266;
- optional int32 ro_boot_qf_st = 267;
- optional int32 ro_boot_ramdump_enable = 268;
- optional string ro_boot_serialno = 269;
- optional string ro_boot_slot_suffix = 270;
- optional int32 ro_boot_temp_protect_ignore = 271;
- optional string ro_boot_vendor_overlay_theme = 272;
- optional string ro_boot_verifiedbootstate = 273;
- optional string ro_boot_veritymode = 274;
- optional string ro_boot_wificountrycode = 275;
+ message Ro {
+ optional int32 adb_secure = 1;
+ optional string arch = 2;
+ optional bool audio_ignore_effects = 3;
+ optional bool audio_monitorRotation = 4;
+ optional string baseband = 5;
+ optional string board_platform = 6;
- optional string ro_bootimage_build_date = 276;
- optional int64 ro_bootimage_build_date_utc = 277;
- optional string ro_bootimage_build_fingerprint = 278;
+ message Boot {
+ optional string avb_version = 1;
+ optional string baseband = 2;
+ optional string bootdevice = 3;
+ optional string bootloader = 4;
+ repeated string boottime = 5;
+ optional string console = 6;
+ optional int32 fake_battery = 7;
+ optional string hardware = 8;
+ optional string hardware_color = 9;
+ optional string hardware_revision = 10;
+ optional string hardware_sku = 11;
+ optional string keymaster = 12;
+ optional string mode = 13;
+ optional string revision = 14;
+ optional string slot_suffix = 15;
+ optional string vbmeta_avb_version = 16;
+ optional string vendor_overlay_theme = 17;
+ optional string verifiedbootstate = 18;
+ optional string veritymode = 19;
+ optional string wificountrycode = 20;
- optional string ro_bootloader = 279;
- optional string ro_bootmode = 280;
+ // Next Tag: 21
+ }
+ optional Boot boot = 7;
- optional int64 ro_boottime_adbd = 281;
- optional int64 ro_boottime_audioserver = 282;
- optional int64 ro_boottime_bootanim = 283;
- optional int64 ro_boottime_bufferhubd = 284;
- optional int64 ro_boottime_cameraserver = 285;
- optional int64 ro_boottime_clear_bcb = 286;
- optional int64 ro_boottime_drm = 287;
- optional int64 ro_boottime_gatekeeperd = 288;
- optional int64 ro_boottime_healthd = 289;
- optional int64 ro_boottime_hidl_memory = 290;
- optional int64 ro_boottime_hwservicemanager = 291;
- optional int64 ro_boottime_init = 292;
- optional int64 ro_boottime_init_cold_boot_wait = 293;
- optional int32 ro_boottime_init_mount_all_early = 294;
- optional int32 ro_boottime_init_mount_all_late = 295;
- optional int32 ro_boottime_init_selinux = 296;
- optional int64 ro_boottime_installd = 297;
- optional int64 ro_boottime_keystore = 298;
- optional int64 ro_boottime_lmkd = 299;
- optional int64 ro_boottime_logd = 300;
- optional int64 ro_boottime_logd_reinit = 301;
- optional int64 ro_boottime_media = 302;
- optional int64 ro_boottime_mediadrm = 303;
- optional int64 ro_boottime_mediaextractor = 304;
- optional int64 ro_boottime_mediametrics = 305;
- optional int64 ro_boottime_netd = 306;
- optional int64 ro_boottime_performanced = 307;
- optional int64 ro_boottime_ril_daemon = 308;
- optional int64 ro_boottime_servicemanager = 309;
- optional int64 ro_boottime_storaged = 310;
- optional int64 ro_boottime_surfaceflinger = 311;
- optional int64 ro_boottime_thermalservice = 312;
- optional int64 ro_boottime_tombstoned = 313;
- optional int64 ro_boottime_ueventd = 314;
- optional int64 ro_boottime_update_engine = 315;
- optional int64 ro_boottime_update_verifier_nonencrypted = 316;
- optional int64 ro_boottime_vendor_adsprpcd = 317;
- optional int64 ro_boottime_vendor_atfwd = 318;
- optional int64 ro_boottime_vendor_audio_hal_2_0 = 319;
- optional int64 ro_boottime_vendor_bluetooth_1_0 = 320;
- optional int64 ro_boottime_vendor_boot_hal_1_0 = 321;
- optional int64 ro_boottime_vendor_camera_provider_2_4 = 322;
- optional int64 ro_boottime_vendor_cas_hal_1_0 = 323;
- optional int64 ro_boottime_vendor_cnd = 324;
- optional int64 ro_boottime_vendor_cnss_daemon = 325;
- optional int64 ro_boottime_vendor_cnss_diag = 326;
- optional int64 ro_boottime_vendor_configstore_hal = 327;
- optional int64 ro_boottime_vendor_contexthub_hal_1_0 = 328;
- optional int64 ro_boottime_vendor_devstart_sh = 329;
- optional int64 ro_boottime_vendor_drm_hal_1_0 = 330;
- optional int64 ro_boottime_vendor_drm_widevine_hal_1_0 = 331;
- optional int64 ro_boottime_vendor_dumpstate_1_0 = 332;
- optional int64 ro_boottime_vendor_flash_nanohub_fw = 333;
- optional int64 ro_boottime_vendor_foreground_sh = 334;
- optional int64 ro_boottime_vendor_fps_hal = 335;
- optional int64 ro_boottime_vendor_gatekeeper_1_0 = 336;
- optional int64 ro_boottime_vendor_gnss_service = 337;
- optional int64 ro_boottime_vendor_gralloc_2_0 = 338;
- optional int64 ro_boottime_vendor_hci_filter_root = 339;
- optional int64 ro_boottime_vendor_hwcomposer_2_1 = 340;
- optional int64 ro_boottime_vendor_imsdatadaemon = 341;
- optional int64 ro_boottime_vendor_imsqmidaemon = 342;
- optional int64 ro_boottime_vendor_init_radio_sh = 343;
- optional int64 ro_boottime_vendor_irsc_util = 344;
- optional int64 ro_boottime_vendor_keymaster_3_0 = 345;
- optional int64 ro_boottime_vendor_light_hal_2_0 = 346;
- optional int64 ro_boottime_vendor_loc_launcher = 347;
- optional int64 ro_boottime_vendor_media_omx = 348;
- optional int64 ro_boottime_vendor_memtrack_hal_1_0 = 349;
- optional int64 ro_boottime_vendor_mid_sh = 350;
- optional int64 ro_boottime_vendor_msm_irqbalance = 351;
- optional int64 ro_boottime_vendor_nanohub_slpi = 352;
- optional int64 ro_boottime_vendor_netmgrd = 353;
- optional int64 ro_boottime_vendor_nfc_hal_service = 354;
- optional int64 ro_boottime_vendor_per_mgr = 355;
- optional int64 ro_boottime_vendor_per_proxy = 356;
- optional int64 ro_boottime_vendor_perfd = 357;
- optional int64 ro_boottime_vendor_port_bridge = 358;
- optional int64 ro_boottime_vendor_power_hal_1_1 = 359;
- optional int64 ro_boottime_vendor_power_sh = 360;
- optional int64 ro_boottime_vendor_qseecomd = 361;
- optional int64 ro_boottime_vendor_ramdump_auto = 362;
- optional int64 ro_boottime_vendor_rmt_storage = 363;
- optional int64 ro_boottime_vendor_sensors_hal_1_0 = 364;
- optional int64 ro_boottime_vendor_ss_ramdump = 365;
- optional int64 ro_boottime_vendor_ssr_setup = 366;
- optional int64 ro_boottime_vendor_thermal_engine = 367;
- optional int64 ro_boottime_vendor_time_daemon = 368;
- optional int64 ro_boottime_vendor_usb_hal_1_1 = 369;
- optional int64 ro_boottime_vendor_vibrator_1_0 = 370;
- optional int64 ro_boottime_vendor_vr_1_0 = 371;
- optional int64 ro_boottime_vendor_wifi_hal_legacy = 372;
- optional int64 ro_boottime_virtual_touchpad = 373;
- optional int64 ro_boottime_vndservicemanager = 374;
- optional int64 ro_boottime_vold = 375;
- optional int64 ro_boottime_vr_hwc = 376;
- optional int64 ro_boottime_webview_zygote32 = 377;
- optional int64 ro_boottime_wificond = 378;
- optional int64 ro_boottime_wpa_supplicant = 379;
- optional int64 ro_boottime_zygote = 380;
- optional int64 ro_boottime_zygote_secondary = 381;
+ message BootImage {
+ optional string build_date = 1;
+ optional int32 build_date_utc = 2;
+ optional string build_fingerprint = 3;
- optional string ro_bt_bdaddr_path = 382;
+ // Next Tag: 4
+ }
+ optional BootImage bootimage = 8;
- optional bool ro_build_ab_update = 383;
- optional string ro_build_characteristics = 384;
- optional string ro_build_date = 385;
- optional int64 ro_build_date_utc = 386;
- optional string ro_build_description = 387;
- optional string ro_build_display_id = 388;
- optional string ro_build_expect_baseband = 389;
- optional string ro_build_expect_bootloader = 390;
- optional string ro_build_fingerprint = 391;
- optional string ro_build_flavor = 392;
- optional string ro_build_host = 393;
- optional string ro_build_id = 394;
- optional string ro_build_product = 395;
- optional bool ro_build_system_root_image = 396;
- optional string ro_build_tags = 397;
- optional string ro_build_type = 398;
- optional string ro_build_user = 399;
- optional string ro_build_version_all_codenames = 400;
- optional string ro_build_version_base_os = 401;
- optional string ro_build_version_codename = 402;
- optional string ro_build_version_incremental = 403;
- optional int32 ro_build_version_preview_sdk = 404;
- optional string ro_build_version_release = 405;
- optional int32 ro_build_version_sdk = 406;
- optional string ro_build_version_security_patch = 407;
+ optional string bootloader = 9;
+ optional string bootmode = 10;
- optional int32 ro_camera_notify_nfc = 408;
- optional string ro_carrier = 409;
- optional bool ro_com_android_dataroaming = 410;
- optional bool ro_com_android_prov_mobiledata = 411;
- optional string ro_com_google_clientidbase = 412;
- optional int32 ro_com_google_ime_theme_id = 413;
+ message Build {
+ optional string date = 1;
+ optional int32 date_utc = 2;
+ optional string description = 3;
+ optional string display_id = 4;
+ optional string host = 5;
+ optional string id = 6;
+ optional string product = 7;
+ optional bool system_root_image = 8;
+ optional string tags = 9;
+ optional string type = 10;
+ optional string user = 11;
- optional string ro_config_alarm_alert = 414;
- optional string ro_config_notification_sound = 415;
- optional string ro_config_ringtone = 416;
- optional int32 ro_config_vc_call_vol_steps = 417;
- optional string ro_control_privapp_permissions = 418;
- optional int32 ro_cp_system_other_odex = 419;
+ message Version {
+ optional string base_os = 1;
+ optional string codename = 2;
+ optional string incremental = 3;
+ optional int32 preview_sdk = 4;
+ optional string release = 5;
+ optional int32 sdk = 6;
+ optional string security_patch = 7;
- optional string ro_crypto_scrypt_params = 420;
- optional string ro_crypto_state = 421;
- optional string ro_crypto_type = 422;
- optional string ro_crypto_volume_filenames_mode = 423;
- optional int32 ro_dalvik_vm_native_bridge = 424;
- optional int32 ro_debuggable = 425;
- optional bool ro_device_owner = 426;
- optional string ro_error_receiver_system_apps = 427;
+ // Next Tag: 8
+ }
+ optional Version version = 12;
- optional int32 ro_facelock_black_timeout = 428;
- optional int32 ro_facelock_det_timeout = 429;
- optional int32 ro_facelock_est_max_time = 430;
- optional int32 ro_facelock_rec_timeout = 431;
+ // Next Tag: 13
+ }
+ optional Build build = 11;
- optional string ro_frp_pst = 432;
+ optional int32 camera_notify_nfc = 12;
+ optional string carrier = 13;
+ optional bool com_android_dataroaming = 14;
+ optional bool com_android_prov_mobiledata = 15;
+ optional string com_google_clientidbase = 16;
- optional string ro_hardware = 433;
- optional string ro_hardware_power = 434;
+ message Config {
+ optional string alarm_alert = 1;
+ optional int32 media_vol_steps = 2;
+ optional string notification_sound = 3;
+ optional string ringtone = 4;
+ optional int32 vc_call_vol_steps = 5;
- optional int32 ro_hwui_drop_shadow_cache_size = 435;
- optional int32 ro_hwui_gradient_cache_size = 436;
- optional int32 ro_hwui_layer_cache_size = 437;
- optional int32 ro_hwui_path_cache_size = 438;
- optional int32 ro_hwui_r_buffer_cache_size = 439;
- optional int32 ro_hwui_text_large_cache_height = 440;
- optional int32 ro_hwui_text_large_cache_width = 441;
- optional int32 ro_hwui_text_small_cache_height = 442;
- optional int32 ro_hwui_text_small_cache_width = 443;
- optional float ro_hwui_texture_cache_flushrate = 444;
- optional int32 ro_hwui_texture_cache_size = 445;
+ // Next Tag: 6
+ }
+ optional Config config = 17;
- optional bool ro_init_subcontexts_enabled = 446;
- optional int32 ro_kernel_android_checkjni = 447;
- optional string ro_logd_size = 448;
- optional int32 ro_min_freq_0 = 449;
- optional int32 ro_oem_unlock_supported = 450;
- optional bool ro_opa_eligible_device = 451;
- optional int32 ro_opengles_version = 452;
- optional bool ro_persistent_properties_ready = 453;
+ optional string control_privapp_permissions = 18;
+ optional int32 cp_system_other_odex = 19;
+ optional string crypto_scrypt_params = 20;
+ optional string crypto_state = 21;
+ optional string crypto_type = 22;
+ optional string dalvik_vm_native_bridge = 23;
+ optional int32 debuggable = 24;
+ optional string frp_pst = 25;
+ optional string gfx_driver_0 = 26;
- optional string ro_product_board = 454;
- optional string ro_product_brand = 455;
- optional string ro_product_cpu_abi = 456;
- repeated string ro_product_cpu_abilist = 457;
- repeated string ro_product_cpu_abilist32 = 458;
- optional string ro_product_cpu_abilist64 = 459;
- optional string ro_product_device = 460;
- optional int32 ro_product_first_api_level = 461;
- optional string ro_product_locale = 462;
- optional string ro_product_manufacturer = 463;
- optional string ro_product_model = 464;
- optional string ro_product_name = 465;
- optional string ro_product_vendor_brand = 466;
- optional string ro_product_vendor_device = 467;
- optional string ro_product_vendor_manufacturer = 468;
- optional string ro_product_vendor_model = 469;
- optional string ro_product_vendor_name = 470;
+ message Hardware {
+ optional string value = 1; // value of ro.hardware itself
- optional int32 ro_property_service_version = 471;
- optional string ro_qc_sdk_audio_fluencetype = 472;
- optional int32 ro_qcom_adreno_qgl_ShaderStorageImageExtendedFormats = 473;
- optional bool ro_qualcomm_bluetooth_ftp = 474;
- optional bool ro_qualcomm_bluetooth_hfp = 475;
- optional bool ro_qualcomm_bluetooth_hsp = 476;
- optional bool ro_qualcomm_bluetooth_map = 477;
- optional bool ro_qualcomm_bluetooth_nap = 478;
- optional bool ro_qualcomm_bluetooth_opp = 479;
- optional bool ro_qualcomm_bluetooth_pbap = 480;
+ optional string activity_recognition = 2;
+ optional string audio = 3;
+ optional string audio_policy = 4;
+ optional string audio_a2dp = 5;
+ optional string audio_primary = 6;
+ optional string audio_usb = 7;
+ optional string bootctrl = 8;
+ optional string camera = 9;
+ optional string consumerir = 10;
+ optional string context_hub = 11;
+ optional string egl = 12;
+ optional string fingerprint = 13;
+ optional string flp = 14;
+ optional string gatekeeper = 15;
+ optional string gps = 16;
+ optional string gralloc = 17;
+ optional string hdmi_cec = 18;
+ optional string hwcomposer = 19;
+ optional string input = 20;
+ optional string keystore = 21;
+ optional string lights = 22;
+ optional string local_time = 23;
+ optional string memtrack = 24;
+ optional string nfc = 25;
+ optional string nfc_nci = 26;
+ optional string nfc_tag = 27;
+ optional string nvram = 28;
+ optional string power = 29;
+ optional string radio = 30;
+ optional string sensors = 31;
+ optional string sound_trigger = 32;
+ optional string thermal = 33;
+ optional string tv_input = 34;
+ optional string type = 35;
+ optional string vehicle = 36;
+ optional string vibrator = 37;
+ optional string virtual_device = 38;
+ optional string vulkan = 39;
- optional string ro_radio_log_loc = 481;
- optional string ro_radio_log_prefix = 482;
- optional int32 ro_revision = 483;
- optional bool ro_ril_svdo = 484;
- optional bool ro_ril_svlte1x = 485;
- optional int64 ro_runtime_firstboot = 486;
- optional int32 ro_secure = 487;
- optional string ro_serialno = 488;
- optional int32 ro_setupwizard_enterprise_mode = 489;
- optional bool ro_setupwizard_rotation_locked = 490;
- optional int32 ro_sf_lcd_density = 491;
- optional bool ro_storage_manager_enabled = 492;
- optional bool ro_telephony_call_ring_multiple = 493;
- optional int32 ro_telephony_default_cdma_sub = 494;
- optional int32 ro_telephony_default_network = 495;
- optional bool ro_treble_enabled = 496;
- optional string ro_url_legal = 497;
- optional string ro_url_legal_android_privacy = 498;
- optional string ro_vendor_build_date = 499;
- optional int64 ro_vendor_build_date_utc = 500;
- optional string ro_vendor_build_fingerprint = 501;
- optional string ro_vendor_extension_library = 502;
- optional bool ro_wallpapers_loc_request_suw = 503;
- optional string ro_wifi_channels = 504;
- optional string ro_zygote = 505;
+ // Next Tag: 40
+ }
+ optional Hardware hardware = 27;
- optional int32 sdm_debug_disable_rotator_split = 506;
+ optional int32 kernel_qemu = 28;
+ optional int32 kernel_qemu_gles = 29;
+ optional int32 oem_unlock_supported = 30;
+ optional int32 opengles_version = 31;
- optional string selinux_restorecon_recursive = 507;
+ message Product {
+ optional string board = 1;
+ optional string brand = 2;
+ optional string cpu_abi = 3;
+ repeated string cpu_abilist = 4;
+ repeated string cpu_abilist32 = 5;
+ repeated string cpu_abilist64 = 6;
+ optional string device = 7;
+ optional int32 first_api_level = 8;
+ optional string manufacturer = 9;
+ optional string model = 10;
+ optional string name = 11;
- optional string sendbug_preferred_domain = 508;
+ message Vendor {
+ optional string brand = 1;
+ optional string device = 2;
+ optional string manufacturer = 3;
+ optional string model = 4;
+ optional string name = 5;
+ }
+ optional Vendor vendor = 12;
- optional string sensors_contexthub_lid_state = 509;
+ // Next Tag: 13
+ }
+ optional Product product = 32;
- optional int32 service_bootanim_exit = 510;
- optional int32 service_sf_present_timestamp = 511;
+ optional int32 property_service_version = 33;
+ optional string retaildemo_video_path = 34;
+ optional string revision = 35;
+ optional int32 sf_lcd_density = 36;
+ optional bool storage_manager_enabled = 37;
+ optional bool telephony_call_ring_multiple = 38;
+ optional int32 telephony_default_cdma_sub = 39;
+ optional int32 telephony_default_network = 40;
+ optional string url_legal = 41;
+ optional string url_legal_android_privacy = 42;
+ optional string vendor_build_date = 43;
+ optional int32 vendor_build_date_utc = 44;
+ optional string vendor_build_fingerprint = 45;
+ optional string vndk_version = 46;
+ optional int32 vts_coverage = 47;
+ optional string zygote = 48;
- optional string setupwizard_theme = 512;
+ // Next Tag: 49
+ }
+ optional Ro ro = 21;
- optional string sys_boot_reason = 513;
- optional int32 sys_boot_completed = 514;
- optional int32 sys_ims_QMI_DAEMON_STATUS = 515;
- optional bool sys_keymaster_loaded = 516;
- optional bool sys_listeners_registered = 517;
- optional int32 sys_logbootcomplete = 518;
- optional int32 sys_oem_unlock_allowed = 519;
- optional int32 sys_post_boot_parsed = 520;
- optional int32 sys_qcom_devup = 521;
- optional int32 sys_retaildemo_enabled = 522;
- optional string sys_slpi_firmware_version = 523;
- optional int32 sys_sysctl_extra_free_kbytes = 524;
- optional int32 sys_sysctl_tcp_def_init_rwnd = 525;
- optional bool sys_time_set = 526;
- optional string sys_usb_config = 527;
- optional int32 sys_usb_configfs = 528;
- optional string sys_usb_controller = 529;
- optional int32 sys_usb_ffs_max_read = 530;
- optional int32 sys_usb_ffs_max_write = 531;
- optional int32 sys_usb_ffs_mtp_ready = 532;
- optional int32 sys_usb_ffs_ready = 533;
- optional int32 sys_usb_mtp_device_type = 534;
- optional int32 sys_usb_rps_mask = 535;
- optional string sys_usb_state = 536;
- optional bool sys_user_0_ce_available = 537;
- optional int32 sys_wifitracing_started = 538;
+ optional string sendbug_preferred_domain = 22;
+ optional int32 service_bootanim_exit = 23;
- optional int32 telephony_lteOnCdmaDevice = 539;
+ message Sys {
+ optional int32 boot_completed = 1;
+ optional int32 boot_from_charger_mode = 2;
+ optional int32 retaildemo_enabled = 3;
+ optional string shutdown_requested = 4;
- optional int32 tombstoned_max_tombstone_count = 540;
+ message Usb {
+ optional string config = 1;
+ optional int32 configfs = 2;
+ optional string controller = 3;
+ optional int32 ffs_max_read = 4;
+ optional int32 ffs_max_write = 5;
+ optional int32 ffs_mtp_ready = 6;
+ optional int32 ffs_ready = 7;
+ optional int32 mtp_device_type = 8;
+ optional string state = 9;
- optional int32 vidc_debug_perf_mode = 541;
+ // Next Tag: 10
+ }
+ optional Usb usb = 5;
- optional int32 vold_has_adoptable = 542;
- optional int32 vold_has_quota = 543;
- optional int32 vold_post_fs_data_done = 544;
+ // Next Tag: 6
+ }
+ optional Sys sys = 24;
- optional int32 wc_transport_clean_up = 545;
- optional int32 wc_transport_hci_filter_status = 546;
- optional string wc_transport_patch_dnld_inprog = 547;
- optional int32 wc_transport_ref_count = 548;
- optional int32 wc_transport_soc_initialized = 549;
- optional bool wc_transport_start_root = 550;
- optional int32 wc_transport_vnd_power = 551;
+ optional int32 telephony_lteOnCdmaDevice = 25;
+ optional int32 tombstoned_max_tombstone_count = 26;
+ optional string vold_decrypt = 27;
+ optional int32 vold_post_fs_data_done = 28;
+ optional int32 vts_native_server_on = 29;
+ optional string wifi_direct_interface = 30;
+ optional string wifi_interface = 31;
- optional string wifi_interface = 552;
- optional string wlan_driver_status = 553;
-
- // Next Tag: 554
+ // Next Tag: 32
}
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index 3229140..fb0ebed 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -367,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,8 +387,9 @@
optional SettingProto enable_cache_quota_calculation = 339;
optional SettingProto enable_deletion_helper_no_threshold_toggle = 340;
optional SettingProto notification_snooze_options = 341;
+ optional SettingProto enable_gnss_raw_meas_full_tracking = 346;
- // Next tag = 346;
+ // Next tag = 347;
}
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 d724437..87d302e 100644
--- a/core/proto/android/server/alarmmanagerservice.proto
+++ b/core/proto/android/server/alarmmanagerservice.proto
@@ -37,71 +37,71 @@
// Dump from ForceAppStandbyTracker.
optional ForceAppStandbyTrackerProto force_app_standby_tracker = 6;
- optional bool is_interactive = 8;
+ optional bool is_interactive = 7;
// Only valid if is_interactive is false.
- optional int64 time_since_non_interactive_ms = 9;
+ optional int64 time_since_non_interactive_ms = 8;
// Only valid if is_interactive is false.
- optional int64 max_wakeup_delay_ms = 10;
+ optional int64 max_wakeup_delay_ms = 9;
// Only valid if is_interactive is false.
- optional int64 time_since_last_dispatch_ms = 11;
+ optional int64 time_since_last_dispatch_ms = 10;
// Only valid if is_interactive is false.
- optional int64 time_until_next_non_wakeup_delivery_ms = 12;
+ optional int64 time_until_next_non_wakeup_delivery_ms = 11;
- optional int64 time_until_next_non_wakeup_alarm_ms = 13;
- optional int64 time_until_next_wakeup_ms = 14;
- optional int64 time_since_last_wakeup_ms = 15;
+ optional int64 time_until_next_non_wakeup_alarm_ms = 12;
+ optional int64 time_until_next_wakeup_ms = 13;
+ optional int64 time_since_last_wakeup_ms = 14;
// Time since the last wakeup was set.
- optional int64 time_since_last_wakeup_set_ms = 16;
- optional int64 time_change_event_count = 17;
+ optional int64 time_since_last_wakeup_set_ms = 15;
+ optional int64 time_change_event_count = 16;
// The current set of user whitelisted apps for device idle mode, meaning
// these are allowed to freely schedule alarms. These are app IDs, not UIDs.
- repeated int32 device_idle_user_whitelist_app_ids = 18;
+ repeated int32 device_idle_user_whitelist_app_ids = 17;
- repeated AlarmClockMetadataProto next_alarm_clock_metadata = 19;
+ repeated AlarmClockMetadataProto next_alarm_clock_metadata = 18;
- repeated BatchProto pending_alarm_batches = 20;
+ repeated BatchProto pending_alarm_batches = 19;
// List of alarms per uid deferred due to user applied background restrictions
// on the source app.
- repeated AlarmProto pending_user_blocked_background_alarms = 21;
+ repeated AlarmProto pending_user_blocked_background_alarms = 20;
// When idling mode will end. Will be empty if the device is not currently
// idling.
- optional AlarmProto pending_idle_until = 22;
+ optional AlarmProto pending_idle_until = 21;
// Any alarms that we don't want to run during idle mode. Will be empty if the
// device is not currently idling.
- repeated AlarmProto pending_while_idle_alarms = 23;
+ repeated AlarmProto pending_while_idle_alarms = 22;
// This is a special alarm that will put the system into idle until it goes
// off. The caller has given the time they want this to happen at.
- optional AlarmProto next_wake_from_idle = 24;
+ optional AlarmProto next_wake_from_idle = 23;
- repeated AlarmProto past_due_non_wakeup_alarms = 25;
+ repeated AlarmProto past_due_non_wakeup_alarms = 24;
// Number of delayed alarms.
- optional int32 delayed_alarm_count = 26;
+ optional int32 delayed_alarm_count = 25;
// The total amount of time alarms had been delayed. Overlapping alarms are
// only counted once (ie. If two alarms were meant to trigger at the same time
// but were delayed by 5 seconds, the total time would be 5 seconds).
- optional int64 total_delay_time_ms = 27;
- optional int64 max_delay_duration_ms = 28;
- optional int64 max_non_interactive_duration_ms = 29;
+ optional int64 total_delay_time_ms = 26;
+ optional int64 max_delay_duration_ms = 27;
+ optional int64 max_non_interactive_duration_ms = 28;
- optional int32 broadcast_ref_count = 30;
+ optional int32 broadcast_ref_count = 29;
// Canonical count of (operation.send() - onSendFinished()) and listener
// send/complete/timeout invocations.
- optional int32 pending_intent_send_count = 31;
- optional int32 pending_intent_finish_count = 32;
- optional int32 listener_send_count = 33;
- optional int32 listener_finish_count = 34;
+ optional int32 pending_intent_send_count = 30;
+ optional int32 pending_intent_finish_count = 31;
+ optional int32 listener_send_count = 32;
+ optional int32 listener_finish_count = 33;
- repeated InFlightProto outstanding_deliveries = 35;
+ repeated InFlightProto outstanding_deliveries = 34;
// Minimum time between ALLOW_WHILE_IDLE alarms when system is idling. It
// should be either CosntantsProto.allow_while_idle_short_duration_ms or
// ConstantsProto.allow_while_idle_long_duration_ms.
- optional int64 allow_while_idle_min_duration_ms = 36;
+ optional int64 allow_while_idle_min_duration_ms = 35;
message LastAllowWhileIdleDispatch {
optional int32 uid = 1;
@@ -110,25 +110,25 @@
}
// 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.
- repeated LastAllowWhileIdleDispatch last_allow_while_idle_dispatch_times = 37;
+ repeated LastAllowWhileIdleDispatch last_allow_while_idle_dispatch_times = 36;
- optional com.android.internal.util.LocalLogProto recent_problems = 38;
+ optional com.android.internal.util.LocalLogProto recent_problems = 37;
message TopAlarm {
optional int32 uid = 1;
optional string package_name = 2;
optional FilterStatsProto filter = 3;
}
- repeated TopAlarm top_alarms = 39;
+ repeated TopAlarm top_alarms = 38;
message AlarmStat {
optional BroadcastStatsProto broadcast = 1;
repeated FilterStatsProto filters = 2;
}
- repeated AlarmStat alarm_stats = 40;
+ repeated AlarmStat alarm_stats = 39;
- repeated IdleDispatchEntryProto allow_while_idle_dispatches = 41;
- repeated WakeupEventProto recent_wakeup_history = 42;
+ repeated IdleDispatchEntryProto allow_while_idle_dispatches = 40;
+ repeated WakeupEventProto recent_wakeup_history = 41;
}
// This is a soft wrapper for alarm clock information. It is not representative
@@ -145,8 +145,9 @@
message AlarmProto {
optional string tag = 1;
optional .android.app.AlarmManagerProto.AlarmType type = 2;
- // How long until the alarm goes off, in the 'elapsed' timebase.
- optional int64 when_elapsed_ms = 3;
+ // How long until the alarm goes off, in the 'elapsed' timebase. Can be
+ // negative if 'when' is in the past.
+ optional int64 time_until_when_elapsed_ms = 3;
optional int64 window_length_ms = 4;
optional int64 repeat_interval_ms = 5;
optional int32 count = 6;
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index d3b2cde..c1bd692 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -57,7 +57,7 @@
optional bool is_active = 3;
optional int32 num_wake_locks = 4;
optional bool is_process_state_unknown = 5;
- optional .android.app.ActivityManagerProto.ProcessState process_state = 6;
+ optional .android.app.ProcessState process_state = 6;
}
optional ConstantsProto constants = 1;
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/proto/android/service/graphicsstats.proto b/core/proto/android/service/graphicsstats.proto
index ee9d6fc..801411d 100644
--- a/core/proto/android/service/graphicsstats.proto
+++ b/core/proto/android/service/graphicsstats.proto
@@ -31,7 +31,7 @@
optional string package_name = 1;
// The version code of the app
- optional int32 version_code = 2;
+ optional int64 version_code = 2;
// The start & end timestamps in UTC as
// milliseconds since January 1, 1970
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..15e439e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -407,6 +407,7 @@
<protected-broadcast android:name="android.internal.policy.action.BURN_IN_PROTECTION" />
<protected-broadcast android:name="android.app.action.SYSTEM_UPDATE_POLICY_CHANGED" />
<protected-broadcast android:name="android.app.action.DEVICE_OWNER_CHANGED" />
+ <protected-broadcast android:name="android.app.action.MANAGED_USER_CREATED" />
<!-- Added in N -->
<protected-broadcast android:name="android.intent.action.ANR" />
@@ -1036,7 +1037,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 +1741,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 +2059,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"
@@ -2918,6 +2924,11 @@
<permission android:name="android.permission.BRIGHTNESS_SLIDER_USAGE"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an application to modify the display brightness configuration
+ @hide -->
+ <permission android:name="android.permission.CONFIGURE_DISPLAY_BRIGHTNESS"
+ android:protectionLevel="signature|privileged|development" />
+
<!-- @SystemApi Allows an application to control VPN.
<p>Not for use by third-party applications.</p>
@hide -->
@@ -3611,6 +3622,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/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 5f65553..1646073 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Sit af"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Noodgeval"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Foutverslag"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Beëindig sessie"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Neem foutverslag"</string>
<string name="bugreport_message" msgid="398447048750350456">"Dit sal inligting oor die huidige toestand van jou toestel insamel om as \'n e-posboodskap te stuur. Dit sal \'n tydjie neem vandat die foutverslag begin is totdat dit reg is om gestuur te word; wees asseblief geduldig."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiewe verslag"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Wanneer die kortpad aan is, sal \'n toeganklikheidkenmerk begin word as albei volumeknoppies 3 sekondes lank gedruk word.\n\n Bestaande toeganklikheidkenmerk:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Jy kan die kenmerk in Instellings > Toeganklikheid verander."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Skakel kortpad af"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Gebruik kortpad"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Kleuromkering"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Kleurkorreksie"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Toeganklikheidskortpad het <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aangeskakel"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Toeganklikheidskortpad het <xliff:g id="SERVICE_NAME">%1$s</xliff:g> afgeskakel"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Kies \'n kenmerk om te gebruik wanneer jy op die Toeganklikheid-knoppie tik:"</string>
@@ -1626,7 +1632,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 +1640,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>
@@ -1682,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Weeksaand"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Naweek"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Geleentheid"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Slaap"</string>
<string name="muted_by" msgid="6147073845094180001">"Gedemp deur <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Daar is \'n interne probleem met jou toestel en dit sal dalk onstabiel wees totdat jy \'n fabriekterugstelling doen."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Daar is \'n interne probleem met jou toestel. Kontak jou vervaardiger vir besonderhede."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD-versoek is gewysig tot DIAL-versoek."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD-versoek is gewysig tot SS-versoek."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD-versoek is gewysig tot nuwe USSD-versoek."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD-versoek is gewysig tot Video DIAL-versoek."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-versoek is gewysig tot DIAL-versoek."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS-versoek is gewysig tot Video DIAL-versoek."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-versoek is gewysig tot USSD-versoek."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-versoek is gewysig tot nuwe SS-versoek."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Werkprofiel"</string>
@@ -1782,14 +1790,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..868b065 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"ክፍለ-ጊዜን አብቃ"</string>
<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 +1052,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 +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,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>
@@ -1495,6 +1499,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"ተቃራኒ ቀለም"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"የቀለም ማስተካከያ"</string>
<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 +1632,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 +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>
@@ -1682,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"መተኛት"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD ጥያቄ ወደ ደውል ጥያቄ ተሻሽሎዋል።"</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD ጥያቄ ወደ SS ጥያቄ ተሻሽሎዋል።"</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD ጥያቄ ወደ አዲስ USSD ጥያቄ ተሻሽሎዋል።"</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"የUSSD ጥያቄ ወደ የቪድዪኦ ደውል ጥያቄ ተቀይሯል።"</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS ጥያቄ ወደ ደውል ጥያቄ ተሻሽሎዋል።"</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"የSS ጥያቄ ወደ የቪዲዮ ደውል ጥያቄ ተቀይሯል።"</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS ጥያቄ ወደ USSD ጥያቄ ተሻሽሎዋል።"</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS ጥያቄ ወደ አዲስ SS ጥያቄ ተሻሽሎዋል።"</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"የስራ መገለጫ"</string>
@@ -1782,14 +1790,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..c9611e4 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>
@@ -220,6 +220,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"إنهاء الجلسة"</string>
<string name="bugreport_title" msgid="2667494803742548533">"إعداد تقرير بالأخطاء"</string>
<string name="bugreport_message" msgid="398447048750350456">"سيجمع هذا معلومات حول حالة جهازك الحالي لإرسالها كرسالة إلكترونية، ولكنه سيستغرق وقتًا قليلاً من بدء عرض تقرير بالأخطاء. وحتى يكون جاهزًا للإرسال، يُرجى الانتظار."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"تقرير تفاعلي"</string>
@@ -1131,6 +1132,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 +1208,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 +1222,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>
@@ -1591,6 +1595,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"عكس الألوان"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"تصحيح الألوان"</string>
<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>
@@ -1734,7 +1740,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>
@@ -1813,13 +1819,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"النوم"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"يتم تعديل طلب USSD لطلب الاتصال."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"يتم تعديل طلب USSD إلى طلب SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"يتم تعديل طلب USSD إلى طلب USSD الجديد."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"تم تعديل طلب USSD إلى طلب Video DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"يتم تعديل الطلب SS لطلب الاتصال."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"تم تعديل طلب SS إلى طلب Video DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"يتم تعديل طلب SS إلى طلب USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"يتم تعديل طلب SS إلى طلب SS الجديد."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"الملف الشخصي للعمل"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 40b5473..a90ef03 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Söndür"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Təcili"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Baq hesabatı"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Sessiyanı sonlandırın"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Baqı xəbər verin"</string>
<string name="bugreport_message" msgid="398447048750350456">"Bu, sizin hazırkı cihaz durumu haqqında məlumat toplayacaq ki, elektron məktub şəklində göndərsin. Baq raportuna başlamaq üçün bir az vaxt lazım ola bilər, bir az səbr edin."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"İnteraktiv hesabat"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Qısayol aktiv olduqda hər iki səs düyməsinə 3 saniyə basıb saxlamaqla əlçatımlılıq funksiyası işə başlayacaq.\n\n Cari əlçatımlılıq funksiyası:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funksiyanı Ayarlar və Əçatımlılıq bölməsində dəyişə bilərsiniz."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Qısayolu Deaktiv edin"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Qısayol İstifadə edin"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Rəng İnversiyası"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Rəng korreksiyası"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Əlçatımlıq Qısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> xidmətini aktiv etdi"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Əlçatımlıq Qısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> xidmətini deaktiv etdi"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Əlçatımlılıq düyməsinə kliklədikdə istifadə etmək üçün funksiya seçin:"</string>
@@ -1626,7 +1632,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 +1640,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>
@@ -1682,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Həftəiçi gecəsi"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Həftə sonu"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Tədbir"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Yuxu"</string>
<string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> tərəfindən susdurulub"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Cihazınızın daxili problemi var və istehsalçı sıfırlanması olmayana qədər qeyri-stabil ola bilər."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Cihazınızın daxili problemi var. Əlavə məlumat üçün istehsalçı ilə əlaqə saxlayın."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD sorğusu DIAL sorğusuna dəyişdirildi."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD sorğusu SS sorğusuna dəyişdirildi."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD sorğusu yeni USSD sorğusuna dəyişdirildi."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD sorğusu Video DIAL sorğusuna dəyişdirildi."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS sorğusu DIAL sorğusuna dəyişdirildi."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS sorğusu Video DIAL sorğusuna dəyişdirildi."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS sorğusu USSD sorğusuna dəyişdirildi."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS sorğusu yeni SS sorğusuna dəyişdirildi."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"İş profili"</string>
@@ -1782,14 +1790,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..6725865 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>
@@ -214,6 +214,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Isključi"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Hitni poziv"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Izveštaj o grešci"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Završi sesiju"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Napravi izveštaj o grešci"</string>
<string name="bugreport_message" msgid="398447048750350456">"Ovim će se prikupiti informacije o trenutnom stanju uređaja kako bi bile poslate u poruci e-pošte. Od započinjanja izveštaja o grešci do trenutka za njegovo slanje proći će neko vreme; budite strpljivi."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiv. izveštaj"</string>
@@ -1071,6 +1072,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 +1142,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 +1156,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>
@@ -1519,6 +1523,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Kada je prečica uključena, pritisnite oba dugmeta za jačinu zvuka da biste pokrenuli funkciju pristupačnosti.\n\n Aktuelna funkcija pristupačnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Možete da promenite funkciju u odeljku Podešavanja > 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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inverzija boja"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcija boja"</string>
<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">"Izaberite funkciju koja će se koristiti kada dodirnete dugme za pristupačnost:"</string>
@@ -1659,7 +1665,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>
@@ -1714,13 +1720,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Radni dan uveče"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Vikend"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Događaj"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Spavanje"</string>
<string name="muted_by" msgid="6147073845094180001">"Zvuk je isključio/la <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Došlo je do internog problema u vezi sa uređajem i možda će biti nestabilan dok ne obavite resetovanje na fabrička podešavanja."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Došlo je do internog problema u vezi sa uređajem. Potražite detalje od proizvođača."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD zahtev je promenjen u DIAL zahtev."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD zahtev je promenjen u SS zahtev."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD zahtev je promenjen u novi USSD zahtev."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD zahtev je promenjen u Video DIAL zahtev."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS zahtev je promenjen u DIAL zahtev."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS zahtev je promenjen u Video DIAL zahtev."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS zahtev je promenjen u USSD zahtev."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS zahtev je promenjen u novi SS zahtev."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profil za Work"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 10ead45..ca75fac 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>
@@ -216,6 +216,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Выключыць"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"SOS-выклік"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Справаздача пра памылкі"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Скончыць сеанс"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Справаздача пра памылку"</string>
<string name="bugreport_message" msgid="398447048750350456">"Будзе збiрацца iнфармацыя пра бягучы стан прылады, якая будзе адпраўляцца на электронную пошту. Стварэнне справаздачы пра памылкi зойме некаторы час."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Інтэрактыўная справаздача"</string>
@@ -1091,6 +1092,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 +1164,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 +1178,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 +1547,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Інверсія колеру"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Карэкцыя колеру"</string>
<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>
@@ -1684,7 +1690,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>
@@ -1747,13 +1753,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Рэжым сну"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Запыт USSD зменены на запыт DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Запыт USSD зменены на запыт SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Запыт USSD зменены на новы запыт USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Запыт USSD зменены на запыт Video DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Запыт SS зменены на запыт DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Запыт SS зменены на запыт Video DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Запыт SS зменены на запыт USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Запыт SS зменены на новы запыт SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Працоўны профіль"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index ccdeb24..44f183f 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"Прекратяване на сесията"</string>
<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 +1052,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 +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="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 +1134,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>
@@ -1495,6 +1499,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Инвертиране на цветовете"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Коригиране на цветовете"</string>
<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 +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">"Запитване за ПИН код преди освобождаване"</string>
@@ -1635,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>
@@ -1682,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Време за сън"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD заявката е променена на DIAL заявка."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD заявката е променена на SS заявка."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD заявката е променена на нова USSD заявка."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD заявката е променена на DIAL заявка за видеообаждане."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS заявката е променена на DIAL заявка."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS заявката е променена на DIAL заявка за видеообаждане."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS заявката е променена на USSD заявка."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS заявката е променена на нова SS заявка."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Служебен потребителски профил"</string>
@@ -1782,14 +1790,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..073fa12 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,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"সেশন শেষ করুন"</string>
<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 +1052,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 +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>
@@ -1505,6 +1500,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"রঙ উল্টানো"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"রঙ সংশোধন"</string>
<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 +1641,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,13 +1688,18 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"ঘুমানোর সময়"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD অনুরোধটিকে ডায়াল অনুরোধে রুপান্তরিত করা হয়েছে৷"</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD অনুরোধটিকে SS অনুরোধে রুপান্তরিত করা হয়েছে৷"</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD অনুরোধটিকে নতুন USSD অনুরোধে রুপান্তরিত করা হয়েছে৷"</string>
+ <!-- no translation found for stk_cc_ussd_to_dial_video (585340552561515305) -->
+ <skip />
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS অনুরোধটিকে ডায়াল অনুরোধে রুপান্তরিত করা হয়েছে৷"</string>
+ <!-- no translation found for stk_cc_ss_to_dial_video (4306210904450719045) -->
+ <skip />
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS অনুরোধটিকে নতুন USSD অনুরোধে রুপান্তরিত করা হয়েছে৷"</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS অনুরোধটিকে নতুন SS অনুরোধে রুপান্তরিত করা হয়েছে৷"</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"কর্মস্থলের প্রোফাইল"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index aa83d1d..c93a0e9 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,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"Završi sesiju"</string>
<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 +365,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 +411,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 +833,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 +848,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 +1027,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 +1074,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 +1144,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 +1158,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 +1290,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 +1302,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 +1354,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 +1398,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 +1525,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inverzija boja"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Ispravka boja"</string>
<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 +1667,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,13 +1722,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Spavanje"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD zahtjev je izmijenjen u DIAL zahtjev."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD zahtjev je izmijenjen u SS zahtjev."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD zahtjev je izmijenjen u novi USSD zahtjev."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD zahtjev je izmijenjen u Video DIAL zahtjev."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS zahtjev je izmijenjen u DIAL zahtjev."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS zahtjev je izmijenjen u Video DIAL zahtjev."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS zahtjev je izmijenjen u USSD zahtjev."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS zahtjev je izmijenjen u novi SS zahtjev."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profil za posao"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 8b07393..64d0ccd 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>
@@ -213,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Apaga"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Emergències"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Informe d\'error"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Finalitza la sessió"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Crea informe d\'errors"</string>
<string name="bugreport_message" msgid="398447048750350456">"Es recopilarà informació sobre l\'estat actual del dispositiu i se t\'enviarà per correu electrònic. Passaran uns quants minuts des de l\'inici de l\'informe d\'errors fins al seu enviament, per la qual cosa et recomanem que tinguis paciència."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Informe interactiu"</string>
@@ -1052,12 +1052,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 +1120,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>
@@ -1504,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Si la drecera està activada, prem els dos botons de volum durant 3 segons, per iniciar una funció d\'accessibilitat.\n\n Funció d\'accessibilitat actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Pots canviar la funció a Configuració > Accessibilitat."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Desactiva la drecera"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Utilitza la drecera"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inversió de color"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Correcció del color"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"La drecera d\'accessibilitat ha activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"La drecera d\'accessibilitat ha desactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Tria la funció que s\'utilitzarà quan toquis el botó Accessibilitat:"</string>
@@ -1643,7 +1640,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>
@@ -1690,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Nit entre setmana"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Cap de setmana"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Esdeveniment"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Mentre dormo"</string>
<string name="muted_by" msgid="6147073845094180001">"Silenciat per <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"S\'ha produït un error intern al dispositiu i és possible que funcioni de manera inestable fins que restableixis les dades de fàbrica."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"S\'ha produït un error intern al dispositiu. Contacta amb el fabricant del dispositiu per obtenir més informació."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"La sol·licitud USSD s\'ha transformat en una sol·licitud DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"La sol·licitud USSD s\'ha transformat en una sol·licitud SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"La sol·licitud USSD s\'ha transformat en una sol·licitud USSD nova."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"La sol·licitud USSD s\'ha transformat en una sol·licitud DIAL de vídeo."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La sol·licitud SS s\'ha transformat en una sol·licitud DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"La sol·licitud SS s\'ha transformat en una sol·licitud DIAL de vídeo."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La sol·licitud SS s\'ha transformat en una sol·licitud USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La sol·licitud SS s\'ha transformat en una sol·licitud SS nova."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Perfil professional"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index a7021e9..0f24965 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>
@@ -216,6 +216,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Vypnout"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Stav nouze"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Hlášení chyb"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Ukončit relaci"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Vytvořit chybové hlášení"</string>
<string name="bugreport_message" msgid="398447048750350456">"Shromažďuje informace o aktuálním stavu zařízení. Tyto informace je následně možné poslat v e-mailové zprávě, chvíli však potrvá, než bude hlášení o chybě připraveno k odeslání. Buďte prosím trpěliví."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktivní přehled"</string>
@@ -1091,6 +1092,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 +1164,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 +1178,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>
@@ -1543,6 +1547,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Když je tato zkratka zapnutá, můžete funkci přístupnosti spustit tím, že na tři sekundy podržíte obě tlačítka hlasitosti.\n\n Aktuální funkce přístupnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkci můžete změnit v Nastavení > Přístupnost."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Vypnout zkratku"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Použít zkratku"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Převrácení barev"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Oprava barev"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Zkratka přístupnosti zapnula službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Zkratka přístupnosti vypnula službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Určete, jakou funkci aktivujete klepnutím na tlačítko Přístupnost:"</string>
@@ -1676,7 +1682,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 +1690,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>
@@ -1748,13 +1753,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Večer v pracovním týdnu"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Víkend"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Událost"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Spánek"</string>
<string name="muted_by" msgid="6147073845094180001">"Ignorováno stranou <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"V zařízení došlo k internímu problému. Dokud neprovedete obnovení továrních dat, může být nestabilní."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"V zařízení došlo k internímu problému. Další informace vám sdělí výrobce."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Požadavek USSD byl změněn na požadavek DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Požadavek USSD byl změněn na požadavek SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Požadavek USSD byl změněn na nový požadavek USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Požadavek USSD byl změněn na požadavek Video DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Požadavek SS byl změněn na požadavek DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Požadavek SS byl změněn na požadavek Video DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Požadavek SS byl změněn na požadavek USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Požadavek SS byl změněn na nový požadavek SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Pracovní profil"</string>
@@ -1852,14 +1860,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..0581742 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Sluk"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Nødopkald"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Fejlrapport"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Afslut sessionen"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Lav fejlrapport"</string>
<string name="bugreport_message" msgid="398447048750350456">"Der indsamles oplysninger om din enheds aktuelle status, der efterfølgende sendes i en e-mail. Der går lidt tid, fra fejlrapporten påbegyndes, til den er klar til at blive sendt. Tak for tålmodigheden."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiv rapport"</string>
@@ -1051,6 +1052,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 +1099,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Når genvejen er slået til, kan du starte en hjælpefunktion ved at trykke på begge lydstyrkeknapper i tre sekunder.\n\n Nuværende hjælpefunktion:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kan skifte funktion i Indstillinger > Hjælpefunktioner."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Deaktiver genvej"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Brug genvej"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Ombytning af farver"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Korriger farve"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Genvejen til hjælpefunktioner aktiverede <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Genvejen til hjælpefunktioner deaktiverede <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Vælg, hvilken funktion du vil bruge, når du trykker på knappen Hjælpefunktioner:"</string>
@@ -1626,7 +1632,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 +1640,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 +1653,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 +1669,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">
@@ -1682,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Hverdagsaften"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Weekend"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Begivenhed"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Sover"</string>
<string name="muted_by" msgid="6147073845094180001">"Lyden blev afbrudt af <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Der er et internt problem med enheden, og den vil muligvis være ustabil, indtil du gendanner fabriksdataene."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Der er et internt problem med enheden. Kontakt producenten for at få yderligere oplysninger."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD-anmodningen er ændret til en DIAL-anmodning."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD-anmodningen er ændret til en SS-anmodning."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD-anmodningen er ændret til en ny USSD-anmodning."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD-anmodningen er ændret til en Video DIAL-anmodning."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-anmodningen er ændret til en DIAL-anmodning."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS-anmodningen er ændret til en Vidieo DIAL-anmodning."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-anmodningen er ændret til en USSD-anmodning."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-anmodningen er ændret til en ny SS-anmodning."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Arbejdsprofil"</string>
@@ -1782,18 +1790,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..f694064 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Ausschalten"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Notfall"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Fehlerbericht"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Sitzung beenden"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Fehlerbericht abrufen"</string>
<string name="bugreport_message" msgid="398447048750350456">"Bei diesem Fehlerbericht werden Daten zum aktuellen Status deines Geräts erfasst und als E-Mail versandt. Vom Start des Berichts bis zu seinem Versand kann es eine Weile dauern. Bitte habe etwas Geduld."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiver Bericht"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Wenn die Verknüpfung aktiviert ist, kannst du die beiden Lautstärketasten drei Sekunden lang gedrückt halten, um eine Bedienungshilfe zu starten.\n\n Aktuelle Bedienungshilfe:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kannst die Bedienungshilfe unter \"Einstellungen\" > \"Bedienungshilfen\" ändern."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Verknüpfung deaktivieren"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Verknüpfung verwenden"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Farbumkehr"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Farbkorrektur"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> wurde durch die Bedienungshilfenverknüpfung aktiviert"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> wurde durch die Bedienungshilfenverknüpfung deaktiviert"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Wähle eine Funktion aus, die verwendet wird, wenn du auf die Schaltfläche für die Bedienungshilfen tippst:"</string>
@@ -1626,7 +1632,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 +1640,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>
@@ -1682,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Abends unter der Woche"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Wochenende"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Termin"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Beim Schlafen"</string>
<string name="muted_by" msgid="6147073845094180001">"Stummgeschaltet durch <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Es liegt ein internes Problem mit deinem Gerät vor. Möglicherweise verhält es sich instabil, bis du es auf die Werkseinstellungen zurücksetzt."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Es liegt ein internes Problem mit deinem Gerät vor. Bitte wende dich diesbezüglich an den Hersteller."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD-Anfrage wird in DIAL-Anfrage geändert."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD-Anfrage wird in SS-Anfrage geändert."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD-Anfrage wird in neue USSD-Anfrage geändert."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD-Anfrage wird in Video-DIAL-Anfrage geändert."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-Anfrage wird in DIAL-Anfrage geändert."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS-Anfrage wird in Video-DIAL-Anfrage geändert."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-Anfrage wird in USSD-Anfrage geändert."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-Anfrage wird in neue SS-Anfrage geändert."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Arbeitsprofil"</string>
@@ -1782,14 +1790,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..c20a03f 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"Λήξη περιόδου σύνδεσης"</string>
<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 +1052,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 +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="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 +1134,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 +1499,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Αντιστροφή χρωμάτων"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Διόρθωση χρωμάτων"</string>
<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 +1632,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 +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>
@@ -1682,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Ύπνος"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Το αίτημα USSD τροποποιήθηκε σε αίτημα DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Το αίτημα USSD τροποποιήθηκε σε αίτημα SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Το αίτημα USSD τροποποιήθηκε σε νέο αίτημα USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Το αίτημα USSD τροποποιήθηκε σε αίτημα Video DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Το αίτημα SS τροποποιήθηκε σε αίτημα DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Το αίτημα SS τροποποιήθηκε σε αίτημα Video DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Το αίτημα SS τροποποιήθηκε σε αίτημα USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Το αίτημα SS τροποποιήθηκε σε νέο αίτημα SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Προφίλ εργασίας"</string>
@@ -1782,14 +1790,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..58268eb 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Emergencias"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Informe de errores"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Finalizar sesión"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Iniciar informe de errores"</string>
<string name="bugreport_message" msgid="398447048750350456">"Se recopilará información sobre el estado actual de tu dispositivo, que se enviará por correo. Pasarán unos minutos desde que se inicie el informe de errores hasta que se envíe, por lo que te recomendamos que tengas paciencia."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Informe interactivo"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Cuando el acceso directo está activado, puedes presionar los botones de volumen durante 3 segundos para iniciar una función de accesibilidad.\n\n Función de accesibilidad actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puedes cambiar la función en Configuración > Accesibilidad."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Desactivar acceso directo"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Usar acceso directo"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inversión de color"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Corrección de color"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"El acceso directo de accesibilidad activó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"El acceso directo de accesibilidad desactivó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Elige una función para usar cuando presionas el botón Accesibilidad:"</string>
@@ -1626,7 +1632,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 +1640,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>
@@ -1682,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Noche, en la semana"</string>
<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="zen_mode_default_every_night_name" msgid="3012363838882944175">"Dormir"</string>
<string name="muted_by" msgid="6147073845094180001">"Silenciados por <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Existe un problema interno con el dispositivo, de modo que el dispositivo puede estar inestable hasta que restablezcas la configuración de fábrica."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Existe un problema interno con el dispositivo. Comunícate con el fabricante para obtener más información."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"La solicitud USSD cambió por una solicitud DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"La solicitud USSD cambió por una solicitud SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"La solicitud USSD cambió por una nueva solicitud USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Se cambió la solicitud USSD por una solicitud DIAL de video."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La solicitud SS cambió por una solicitud DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Se cambió la solicitud SS por una solicitud DIAL de video."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La solicitud SS cambió por una solicitud USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La solicitud SS cambió por una nueva solicitud SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Perfil de trabajo"</string>
@@ -1782,14 +1790,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..d03498c 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Emergencia"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Informe de error"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Finalizar sesión"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Crear informe de errores"</string>
<string name="bugreport_message" msgid="398447048750350456">"Se recopilará información sobre el estado actual de tu dispositivo y se enviará por correo electrónico. Pasarán unos minutos desde que empiece a generarse el informe de errores hasta que se envíe."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Informe interactivo"</string>
@@ -564,9 +565,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 +745,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 +1052,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 +1120,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 +1134,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 +1483,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Si el acceso directo está activado, pulsa los dos botones de volumen durante tres segundos para iniciar una función de accesibilidad.\n\n Función de accesibilidad actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puedes cambiar la función en Ajustes > Accesibilidad."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Desactivar acceso directo"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Utilizar acceso directo"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inversión de color"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Corrección de color"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"El acceso directo a accesibilidad ha activado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"El acceso directo a accesibilidad ha desactivado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Selecciona la función que se utilizará cuando toques el botón Accesibilidad:"</string>
@@ -1634,7 +1640,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>
@@ -1681,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Noche de entre semana"</string>
<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="zen_mode_default_every_night_name" msgid="3012363838882944175">"Dormir"</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>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"La solicitud USSD se ha modificado para la nueva solicitud USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"La solicitud USSD se ha modificado para la solicitud DIAL de vídeo."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La solicitud SS se ha modificado para la solicitud DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"La solicitud SS se ha modificado para la solicitud DIAL de vídeo."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La solicitud SS se ha modificado para la solicitud USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La solicitud SS se ha modificado para la nueva solicitud SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Perfil de trabajo"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 27ceef2..754cdb3 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Lülita välja"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Hädaabi"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Veaaruanne"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Seansi lõpp"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Veaaruande võtmine"</string>
<string name="bugreport_message" msgid="398447048750350456">"Nii kogutakse teavet teie seadme praeguse oleku kohta, et saata see meilisõnumina. Enne kui saate veaaruande ära saata, võtab selle loomine natuke aega; varuge kannatust."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interakt. aruanne"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Kui otsetee on sisse lülitatud, käivitab mõlema helitugevuse nupu kolm sekundit all hoidmine juurdepääsetavuse funktsiooni.\n\n Praegune juurdepääsetavuse funktsioon:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Saate seda funktsiooni muuta valikutega Seaded > Juurdepääsetavus."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Lülita otsetee välja"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Kasuta otseteed"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Värvide ümberpööramine"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Värviparandus"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Juurdepääsetavuse otsetee lülitas teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> sisse"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Juurdepääsetavuse otsetee lülitas teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> välja"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Valige, millist funktsiooni kasutada, kui vajutate nuppu Juurdepääsetavus:"</string>
@@ -1626,7 +1632,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 +1640,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>
@@ -1682,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Argiõhtu"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Nädalavahetus"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Sündmus"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Magamine"</string>
<string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> vaigistas"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Seadmes ilmnes sisemine probleem ja seade võib olla ebastabiilne seni, kuni lähtestate seadme tehase andmetele."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Seadmes ilmnes sisemine probleem. Üksikasjaliku teabe saamiseks võtke ühendust tootjaga."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD-päring muudeti DIAL-päringuks."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD-päring muudeti SS-päringuks."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD-päring muudeti uueks USSD-päringuks."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD-taotlus muudeti video DIAL-taotluseks."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-päring muudeti DIAL-päringuks."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS-taotlus muudeti video DIAL-taotluseks."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-päring muudeti USSD-päringuks."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-päring muudeti uueks SS-päringuks."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Tööprofiil"</string>
@@ -1782,14 +1790,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..2e10fa2 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Itzali"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Larrialdi-deiak"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Akatsen txostena"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Amaitu saioa"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Sortu akatsen txostena"</string>
<string name="bugreport_message" msgid="398447048750350456">"Gailuaren uneko egoerari buruzko informazioa bilduko da, mezu elektroniko gisa bidaltzeko. Minutu batzuk igaroko dira akatsen txostena sortzen hasten denetik bidaltzeko prest egon arte. Itxaron, mesedez."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Txosten dinamikoa"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1500,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Lasterbidea aktibatuta dagoenean, bi bolumen-botoiak hiru segundoz sakatuta abiaraziko da erabilerraztasun-eginbidea.\n\n Uneko erabilerraztasun-eginbidea:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Eginbidea aldatzeko, joan Ezarpenak > Erabilerraztasuna atalera."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Desaktibatu lasterbidea"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Erabili lasterbidea"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Koloreak alderantzikatzeko aukera"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Kolorearen zuzenketa"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Erabilerraztasun-lasterbideak <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktibatu du"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Erabilerraztasun-lasterbideak <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desaktibatu du"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Aukeratu zein eginbide erabili nahi duzun Erabilerraztasuna botoia sakatzean:"</string>
@@ -1626,7 +1633,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 +1641,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>
@@ -1682,13 +1688,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Lanegunetako gaua"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Asteburua"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Gertaera"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Lo egin bitartean"</string>
<string name="muted_by" msgid="6147073845094180001">"Audioa desaktibatu da (<xliff:g id="THIRD_PARTY">%1$s</xliff:g>)"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Barneko arazo bat dago zure gailuan eta agian ezegonkor egongo da jatorrizko datuak berrezartzen dituzun arte."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Barneko arazo bat dago zure gailuan. Xehetasunak jakiteko, jarri fabrikatzailearekin harremanetan."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD eskaera DIAL eskaerara aldatu da."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD eskaera SS eskaerara aldatu da."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD eskaera USSD eskaera berrira aldatu da."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD eskaera Video DIAL eskaerara aldatu da."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS eskaera DIAL eskaerara aldatu da."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS eskaera Video DIAL eskaerara aldatu da."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS eskaera USSD eskaerara aldatu da."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS eskaera SS eskaera berrira aldatu da."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Work profila"</string>
@@ -1782,14 +1791,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..dfa350b 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,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"پایان جلسه"</string>
<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 +978,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 +1052,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 +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,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 +1499,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"وارونگی رنگ"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"تصحیح رنگ"</string>
<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 +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">"درخواست کد پین قبل از برداشتن پین"</string>
@@ -1635,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>
@@ -1682,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"خوابیدن"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"درخواست USSD به درخواست DIAL اصلاح میشود."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"درخواست USSD به درخواست SS اصلاح میشود."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"درخواست USSD به درخواست USSD جدید اصلاح میشود."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"درخواست USSD به درخواست Video DIAL تغییر کرد."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"درخواست SS به درخواست DIAL اصلاح میشود."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"درخواست SS به درخواست Video DIAL تغییر کرد."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"درخواست SS به درخواست USSD اصلاح میشود."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"درخواست SS به درخواست SS جدید اصلاح میشود."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"نمایه کاری"</string>
@@ -1782,14 +1790,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..5696b5a 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Katkaise virta"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Hätäpuhelu"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Virheraportti"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Lopeta käyttökerta"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Luo virheraportti"</string>
<string name="bugreport_message" msgid="398447048750350456">"Toiminto kerää tietoja laitteen tilasta ja lähettää ne sähköpostitse. Virheraportti on valmis lähetettäväksi hetken kuluttua - kiitos kärsivällisyydestäsi."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiivinen"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Kun pikanäppäin on käytössä, voit käynnistää esteettömyystoiminnon pitämällä molempia äänenvoimakkuuspainikkeita painettuna kolmen sekunnin ajan.\n\n Tällä hetkellä valittu esteettömyystoiminto:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Voit vaihtaa toimintoa valitsemalla Asetukset > Esteettömyys."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Poista pikanäppäin käytöstä"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Käytä pikanäppäintä"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Käänteiset värit"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Värinkorjaus"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> otettiin käyttöön esteettömyystilan pikanäppäimellä."</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> poistettiin käytöstä esteettömyystilan pikanäppäimellä."</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Valitse toiminto, jonka Esteettömyys-painike aktivoi:"</string>
@@ -1634,7 +1640,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>
@@ -1681,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Arki-iltaisin"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Viikonloppuna"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Tapahtuma"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Nukkuminen"</string>
<string name="muted_by" msgid="6147073845094180001">"Mykistänyt <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Laitteellasi on sisäinen ongelma, joka aiheuttaa epävakautta. Voit korjata tilanteen palauttamalla tehdasasetukset."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Laitteesi yhdistäminen ei onnistu sisäisen virheen takia. Saat lisätietoja valmistajalta."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD-pyyntö muutettiin DIAL-pyynnöksi."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD-pyyntö muutettiin SS-pyynnöksi."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD-pyyntö muutettiin uudeksi USSD-pyynnöksi."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD-pyyntö muutettiin Video DIAL ‑pyynnöksi."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-pyyntö muutettiin DIAL-pyynnöksi."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS-pyyntö muutettiin Video DIAL ‑pyynnöksi."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-pyyntö muutettiin USSD-pyynnöksi."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-pyyntö muutettiin uudeksi SS-pyynnöksi."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Työprofiili"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 658e951..6e97844 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Éteindre"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Urgence"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Rapport de bogue"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Fermer la session"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Créer un rapport de bogue"</string>
<string name="bugreport_message" msgid="398447048750350456">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme de courriel. Merci de patienter pendant la préparation du rapport de bogue. Cette opération peut prendre quelques instants."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Rapport interactif"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour lancer une fonctionnalité d\'accessibilité.\n\n Fonctionnalité d\'accessibilité utilisée actuellement :\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Vous pouvez changer de fonctionnalité sous Paramètres > Accessibilité."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Désactiver le raccourci"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Utiliser le raccourci"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inversion des couleurs"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Correction des couleurs"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Le raccourci d\'accessibilité a activé la fonction <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Le raccourci d\'accessibilité a désactivé la fonction <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choisissez une fonctionnalité à utiliser lorsque vous touchez le bouton d\'accessibilité :"</string>
@@ -1634,7 +1640,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>
@@ -1681,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Soirs de semaine"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Fin de semaine"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Événement"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Dormir"</string>
<string name="muted_by" msgid="6147073845094180001">"Mis en sourdine par <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Un problème interne est survenu avec votre appareil. Il se peut qu\'il soit instable jusqu\'à ce que vous le réinitialisiez à sa configuration d\'usine."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Un problème interne est survenu avec votre appareil. Communiquez avec le fabricant pour obtenir plus de détails."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"La demande USSD a été modifiée et est maintenant une demande DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"La demande USSD a été modifiée et est maintenant une demande SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"La demande USSD a été modifiée et est maintenant une nouvelle demande USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"La demande USSD a été modifiée et est maintenant une demande Video DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La demande SS a été modifiée et est maintenant une demande DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"La demande SS a été modifiée et est maintenant une demande Video DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La demande SS a été modifiée et est maintenant une demande USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La demande SS a été modifiée et est maintenant une nouvelle demande SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profil professionnel"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 34e761b..7dc33c4 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Éteindre"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Urgences"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Rapport de bug"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Fermer la session"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Créer un rapport de bug"</string>
<string name="bugreport_message" msgid="398447048750350456">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme d\'e-mail. Merci de patienter pendant la préparation du rapport de bug. Cette opération peut prendre quelques instants."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Rapport interactif"</string>
@@ -262,7 +263,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 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour lancer une fonctionnalité d\'accessibilité.\n\n Fonctionnalité d\'accessibilité utilisée actuellement :\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Vous pouvez changer de fonctionnalité dans Paramètres > Accessibilité."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Désactiver le raccourci"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Utiliser le raccourci"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inversion des couleurs"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Correction des couleurs"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Le raccourci d\'accessibilité a activé <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Le raccourci d\'accessibilité a désactivé <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choisissez une fonctionnalité à utiliser lorsque vous appuyez sur le bouton d\'accessibilité :"</string>
@@ -1626,7 +1632,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 +1640,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>
@@ -1682,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Soirée de semaine"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Week-end"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Événement"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Sommeil"</string>
<string name="muted_by" msgid="6147073845094180001">"Son coupé par : <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Un problème interne lié à votre appareil est survenu. Ce dernier risque d\'être instable jusqu\'à ce que vous rétablissiez la configuration d\'usine."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Un problème interne lié à votre appareil est survenu. Veuillez contacter le fabricant pour en savoir plus."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"La requête USSD a été remplacée par une requête DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"La requête USSD a été remplacée par une requête SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"La requête USSD a été remplacée par une autre requête USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"La requête SS a été remplacée par une requête vidéo DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La requête SS a été remplacée par une requête DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"La requête SS a été remplacée par une requête vidéo DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La requête SS a été remplacée par une requête USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La requête SS a été remplacée par une autre requête SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profil professionnel"</string>
@@ -1782,18 +1790,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..b5aab39 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Urxencias"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Informe de erros"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Finalizar a sesión"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Crear informe de erros"</string>
<string name="bugreport_message" msgid="398447048750350456">"Este informe recompilará información acerca do estado actual do teu dispositivo para enviala en forma de mensaxe de correo electrónico. O informe de erros tardará un pouco en completarse desde o seu inicio ata que estea preparado para enviarse, polo que che recomendamos que teñas paciencia."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Informe interactivo"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1500,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Cando o atallo está activado, podes premer os dous botóns de volume durante 3 segundos para iniciar unha función de accesibilidade.\n\n Función de accesibilidade actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Podes cambiar a función en Configuración > Accesibilidade."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Desactivar atallo"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Utilizar atallo"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inversión de cor"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Corrección de cor"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atallo de accesibilidade activou <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atallo de accesibilidade desactivou <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolle que función queres utilizar cando toques o botón Accesibilidade:"</string>
@@ -1634,7 +1641,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>
@@ -1681,13 +1688,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Noite da semana"</string>
<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="zen_mode_default_every_night_name" msgid="3012363838882944175">"Durmindo"</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">"Produciuse un erro interno no teu dispositivo e quizais funcione de maneira inestable ata o restablecemento dos datos de fábrica."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Produciuse un erro interno co teu dispositivo. Contacta co teu fabricante para obter máis información."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"A solicitude USSD transformouse nunha solicitude DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"A solicitude USSD transformouse nunha solicitude SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"A solicitude USSD transformouse nunha nova solicitude USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"A solicitude USSD transformouse nunha solicitude DIAL de vídeo."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"A solicitude SS transformouse nunha solicitude DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"A solicitude SS transformouse nunha solicitude DIAL de vídeo."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"A solicitude SS transformouse nunha solicitude USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"A solicitude SS transformouse nunha nova solicitude SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Perfil de traballo"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 1e9b38c..cff1a85 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"સત્ર સમાપ્ત કરો"</string>
<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 +1052,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 +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>
@@ -1495,6 +1500,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"રંગનો વ્યુત્ક્રમ"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"રંગ સુધારણા"</string>
<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>
@@ -1634,7 +1641,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>
@@ -1681,13 +1688,18 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"નિષ્ક્રિય"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD વિનંતીને DIAL વિનંતી પર સંશોધિત કરી."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD વિનંતીને SS વિનંતી પર સંશોધિત કરી."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD વિનંતીને નવી USSD વિનંતી પર સંશોધિત કરી."</string>
+ <!-- no translation found for stk_cc_ussd_to_dial_video (585340552561515305) -->
+ <skip />
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS વિનંતીને DIAL વિનંતી પર સંશોધિત કરી."</string>
+ <!-- no translation found for stk_cc_ss_to_dial_video (4306210904450719045) -->
+ <skip />
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS વિનંતીને USSD વિનંતી પર સંશોધિત કરી."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS વિનંતીને નવી SS વિનંતી પર સંશોધિત કરી."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"કાર્યાલયની પ્રોફાઇલ"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 0a71c74..f9e8a03 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>
@@ -213,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"सत्र खत्म करें"</string>
<string name="bugreport_title" msgid="2667494803742548533">"गड़बड़ी की रिपोर्ट लें"</string>
<string name="bugreport_message" msgid="398447048750350456">"इससे ईमेल भेजने के लिए, आपके डिवाइस की मौजूदा स्थिति से जुड़ी जानकारी इकट्ठा की जाएगी. गड़बड़ी की रिपोर्ट बनना शुरू होने से लेकर भेजने के लिए तैयार होने तक कुछ समय लगेगा; कृपया इंतज़ार करें."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"सहभागी रिपोर्ट"</string>
@@ -236,7 +236,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 +469,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 +487,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 +1052,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 +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>
@@ -1212,9 +1207,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>
@@ -1504,6 +1499,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"रंग बदलने की सुविधा"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"रंग में सुधार करने की सुविधा"</string>
<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>
@@ -1643,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>
@@ -1690,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"सोते समय"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD अनुरोध को DIAL अनुरोध में बदल दिया गया है."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD अनुरोध को SS अनुरोध में बदल दिया गया है."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD अनुरोध को नए USSD अनुरोध में बदल दिया गया है."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD अनुरोध को वीडियो DIAL अनुरोध में बदल दिया गया है."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS अनुरोध को DIAL अनुरोध में बदल दिया गया है."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS अनुरोध को वीडियो DIAL अनुरोध में बदल दिया गया है."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS अनुरोध को USSD अनुरोध में बदल दिया गया है."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS अनुरोध को नए SS अनुरोध में बदल दिया गया है."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"कार्य प्रोफ़ाइल"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 1b92d58..7e53209 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>
@@ -214,6 +214,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Isključi"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Hitno"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Izvješće o bugovima"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Završi sesiju"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Izvješće o programskoj pogrešci"</string>
<string name="bugreport_message" msgid="398447048750350456">"Time će se prikupiti podaci o trenutačnom stanju vašeg uređaja koje ćete nam poslati u e-poruci. Za pripremu izvješća o programskoj pogrešci potrebno je nešto vremena pa vas molimo za strpljenje."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktivno izvješće"</string>
@@ -1071,6 +1072,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 +1142,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 +1156,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>
@@ -1519,6 +1523,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Kada je taj prečac uključen, pritiskom na obje tipke za glasnoću na 3 sekunde pokrenut će se značajka pristupačnosti.\n\n Trenutačna značajka pristupačnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Značajku možete promijeniti u Postavkama > Pristupačnost."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Isključi prečac"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Upotrijebi prečac"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inverzija boja"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcija boje"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečac pristupačnosti uključio je uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečac pristupačnosti isključio je uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Odaberite značajku koju ćete upotrebljavati kada dodirnete gumb Pristupačnost:"</string>
@@ -1651,7 +1657,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 +1665,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>
@@ -1715,13 +1720,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Noć radnog dana"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Vikend"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Događaj"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Spavanje"</string>
<string name="muted_by" msgid="6147073845094180001">"Zvuk je isklj. treća strana <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Na vašem uređaju postoji interni problem i možda neće biti stabilan dok ga ne vratite na tvorničko stanje."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Na vašem uređaju postoji interni problem. Obratite se proizvođaču za više pojedinosti."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD zahtjev izmijenjen je u DIAL zahtjev."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD zahtjev izmijenjen je u SS zahtjev."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD zahtjev izmijenjen je u novi USSD zahtjev."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD zahtjev izmijenjen je u Video DIAL zahtjev."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS zahtjev izmijenjen je u DIAL zahtjev."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS zahtjev izmijenjen je u Video DIAL zahtjev."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS zahtjev izmijenjen je u USSD zahtjev."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS zahtjev izmijenjen je u novi SS zahtjev."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Radni profil"</string>
@@ -1817,14 +1825,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..b815035 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Kikapcsolás"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Segélyhívás"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Programhiba bejelentése"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Munkamenet befejezése"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Hibajelentés készítése"</string>
<string name="bugreport_message" msgid="398447048750350456">"Ezzel információt fog gyűjteni az eszköz jelenlegi állapotáról, amelyet a rendszer e-mailben fog elküldeni. Kérjük, legyen türelemmel, amíg a hibajelentés elkészül, és küldhető állapotba kerül."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktív jelentés"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Ha be van kapcsolva a billentyűparancs, a két hangerőgomb 3 másodpercig tartó lenyomásával elindíthatja a kisegítő lehetőségek egyik funkcióját.\n\n A kisegítő lehetőségek jelenleg beállított funkciója:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n A funkciót a Beállítások > Kisegítő lehetőségek menüpontban módosíthatja."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Billentyűparancs kikapcsolása"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Billentyűparancs használata"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Színek invertálása"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Színkorrekció"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"A Kisegítő lehetőségek gyorsparancsa bekapcsolta a következő szolgáltatást: <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"A Kisegítő lehetőségek gyorsparancsa kikapcsolta a következő szolgáltatást: <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Válassza ki a Kisegítő lehetőségek gombra koppintáskor használni kívánt funkciót:"</string>
@@ -1626,7 +1632,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 +1640,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>
@@ -1682,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Hétköznap éjszaka"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Hétvége"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Esemény"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Alvás"</string>
<string name="muted_by" msgid="6147073845094180001">"A(z) <xliff:g id="THIRD_PARTY">%1$s</xliff:g> elnémította"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Belső probléma van az eszközzel, és instabil lehet, amíg vissza nem állítja a gyári adatokat."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Belső probléma van az eszközzel. A részletekért vegye fel a kapcsolatot a gyártóval."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Az USSD-kérés módosítva DIAL-kérésre."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Az USSD-kérés módosítva SS-kérésre."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Az USSD-kérés módosítva új USSD-kérésre."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD-kérés módosítva Video DIAL-kérésre."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Az SS-kérés módosítva DIAL-kérésre."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS-kérés módosítva Video DIAL-kérésre."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Az SS-kérés módosítva USSD-kérésre."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Az SS-kérés módosítva új SS-kérésre."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Munkaprofil"</string>
@@ -1782,14 +1790,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..ff615c50 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"Ավարտել աշխատաշրջանը"</string>
<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 +1052,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 +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,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>
@@ -1495,6 +1499,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Գունաշրջում"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Գունաշտկում"</string>
<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>
@@ -1634,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>
@@ -1681,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Քնելիս"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD հարցումը փոխվել է DIAL հարցման:"</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD հարցումը փոխվել է SS հարցման:"</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD հարցումը փոխվել է նոր USSD հարցման:"</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD հարցումը փոխվել է Video DIAL հարցման:"</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS հարցումը փոխվել է DIAL հարցման:"</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS հարցումը փոխվել է Video DIAL հարցման:"</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS հարցումը փոխվել է USSD հարցման:"</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS հարցումը փոխվել է նոր SS հարցման:"</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Աշխատանքային պրոֆիլ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 2389d4d..b8b76a0 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,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"Akhiri sesi"</string>
<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 +496,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 +519,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 +797,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 +829,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 +1052,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 +1120,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 +1134,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 +1499,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inversi Warna"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Koreksi Warna"</string>
<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 +1640,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,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Tidur"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Permintaan USSD diubah menjadi permintaan DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Permintaan USSD diubah menjadi permintaan SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Permintaan USSD diubah menjadi permintaan USSD baru."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Permintaan USSD diubah menjadi permintaan DIAL Video."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Permintaan SS diubah menjadi permintaan DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Permintaan SS diubah menjadi permintaan DIAL Video."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Permintaan SS diubah menjadi permintaan USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Permintaan SS diubah menjadi permintaan SS baru."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profil kerja"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 400228a..76286e1 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Slökkva"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Neyðarsímtal"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Villutilkynning"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Ljúka lotu"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Útbúa villutilkynningu"</string>
<string name="bugreport_message" msgid="398447048750350456">"Þetta safnar upplýsingum um núverandi stöðu tækisins til að senda með tölvupósti. Það tekur smástund frá því villutilkynningin er ræst og þar til hún er tilbúin til sendingar – sýndu biðlund."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Gagnvirk skýrsla"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1500,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Þegar flýtileiðin er virk er kveikt á aðgengiseiginleikanum með því að halda báðum hljóðstyrkshnöppunum inni í þrjár sekúndur.\n\n Virkur aðgengiseiginleiki:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Hægt er að skipta um eiginleika í Stillingar > Aðgengi."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Slökkva á flýtileið"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Nota flýtileið"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Umsnúningur lita"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Litaleiðrétting"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Flýtileið aðgengisstillingar kveikti á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Flýtileið aðgengisstillingar slökkti á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Veldu eiginleika sem á að nota þegar ýtt er á aðgengishnappinn:"</string>
@@ -1626,7 +1633,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 +1641,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>
@@ -1682,13 +1688,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Virkt kvöld"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Helgi"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Viðburður"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Svefn"</string>
<string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> tók hljóðið af"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Innra vandamál kom upp í tækinu og það kann að vera óstöðugt þangað til þú núllstillir það."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Innra vandamál kom upp í tækinu. Hafðu samband við framleiðanda til að fá nánari upplýsingar."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD-beiðni er breytt í DIAL-beiðni."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD-beiðni er breytt í SS-beiðni."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD-beiðni er breytt í nýja USSD-beiðni."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD-beiðni var breytt í Video DIAL-beiðni."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-beiðni er breytt í DIAL-beiðni."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS-beiðni var breytt í Video DIAL-beiðni."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-beiðni er breytt í USSD-beiðni."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-beiðni er breytt í nýja SS-beiðni."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Vinnusnið"</string>
@@ -1782,14 +1791,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..2116542 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Spegni"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Emergenza"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Segnalazione di bug"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Termina sessione"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Apri segnalazione bug"</string>
<string name="bugreport_message" msgid="398447048750350456">"Verranno raccolte informazioni sullo stato corrente del dispositivo che saranno inviate sotto forma di messaggio email. Passerà un po\' di tempo prima che la segnalazione di bug aperta sia pronta per essere inviata; ti preghiamo di avere pazienza."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Rapporto interattivo"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Quando la scorciatoia è attiva, puoi premere entrambi i pulsanti del volume per tre secondi per avviare una funzione di accessibilità.\n\n Funzione di accessibilità corrente:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puoi cambiare la funzione in Impostazioni > Accessibilità."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Disattiva scorciatoia"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Usa scorciatoia"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inversione colori"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Correzione colore"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"La scorciatoia Accessibilità ha attivato <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"La scorciatoia Accessibilità ha disattivato <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Scegli una funzione da usare quando tocchi il pulsante Accessibilità:"</string>
@@ -1625,17 +1631,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>
@@ -1682,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Notte di un giorno feriale"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Fine settimana"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Evento"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Sleeping (Notte)"</string>
<string name="muted_by" msgid="6147073845094180001">"Audio disattivato da <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Si è verificato un problema interno con il dispositivo, che potrebbe essere instabile fino al ripristino dei dati di fabbrica."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Si è verificato un problema interno con il dispositivo. Per informazioni dettagliate, contatta il produttore."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"La richiesta USSD è stata modificata in richiesta DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"La richiesta USSD è stata modificata in richiesta SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"La richiesta USSD è stata modificata in nuova richiesta USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"La richiesta USSD è stata modificata in richiesta DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La richiesta SS è stata modificata in richiesta DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"La richiesta SS è stata modificata in richiesta Video DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La richiesta SS è stata modificata in richiesta USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La richiesta SS è stata modificata in nuova richiesta SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profilo di lavoro"</string>
@@ -1732,7 +1740,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 +1790,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..87e20c0 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>
@@ -216,6 +216,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"סיום הפעלה"</string>
<string name="bugreport_title" msgid="2667494803742548533">"שלח דיווח על באג"</string>
<string name="bugreport_message" msgid="398447048750350456">"פעולה זו תאסוף מידע על מצב המכשיר הנוכחי שלך על מנת לשלוח אותו כהודעת אימייל. היא תימשך זמן קצר מרגע פתיחת דיווח הבאג ועד לשליחת ההודעה בפועל. אנא המתן בסבלנות."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"דוח אינטראקטיבי"</string>
@@ -1091,6 +1092,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 +1164,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 +1178,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 +1547,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"היפוך צבעים"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"תיקון צבעים"</string>
<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>
@@ -1684,7 +1690,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>
@@ -1747,13 +1753,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"שינה"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"בקשת USSD שונתה לבקשת DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"בקשת USSD שונתה לבקשת SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"בקשת USSD שונתה לבקשת USSD חדשה."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"בקשת USSD שונתה לבקשת Video DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"בקשת SS שונתה לבקשת DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"בקשת SS שונתה לבקשת Video DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"בקשת SS שונתה לבקשת USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"בקשת SS שונתה לבקשת SS חדשה."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"פרופיל עבודה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index baff85c..c2cc154 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"セッションを終了"</string>
<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 +1052,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 +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,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"ショートカットが ON の場合、両方の音量ボタンを 3 秒間押し続けるとユーザー補助機能が起動します。\n\n現在のユーザー補助機能:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nユーザー補助機能は [設定] > [ユーザー補助] で変更できます。"</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"ショートカットを OFF にする"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"ショートカットを使用"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"色反転"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"色補正"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ユーザー補助機能のショートカットにより <xliff:g id="SERVICE_NAME">%1$s</xliff:g> は ON になっています"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ユーザー補助機能のショートカットにより <xliff:g id="SERVICE_NAME">%1$s</xliff:g> は OFF になっています"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"[ユーザー補助] ボタンをタップした場合に使用する機能を選択してください。"</string>
@@ -1626,7 +1632,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 +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">"バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを抑え、バイブレーション、位置情報サービス、大半のバックグラウンドデータを制限します。メール、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>
@@ -1682,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"睡眠中"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSDリクエストはDIALリクエストに変更されました。"</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSDリクエストはSSリクエストに変更されました。"</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSDリクエストは新しいUSSDリクエストに変更されました。"</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD リクエストは Video DIAL リクエストに変更されました。"</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SSリクエストはDIALリクエストに変更されました。"</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS リクエストは Video DIAL リクエストに変更されました。"</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SSリクエストはUSSDリクエストに変更されました。"</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SSリクエストは新しいSSリクエストに変更されました。"</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"仕事用プロファイル"</string>
@@ -1782,14 +1790,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..ae4fb6f 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,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"სესიის დასრულება"</string>
<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 +1052,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 +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,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 +1499,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"ფერთა ინვერსია"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"ფერთა კორექცია"</string>
<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 +1632,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 +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>
@@ -1682,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"ძილისას"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD მოთხოვნა შეიცვლალა DIAL მოთხოვნით."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD მოთხოვნა შეიცვალა SS მოთხოვნით."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD მოთხოვნა შეიცვალა ახალი USSD მოთხოვნით."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD მოთხოვნა შეიცვალა Video DIAL მოთხოვნით."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS მოთხოვნა შეიცვალა DIAL მოთხოვნით."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS მოთხოვნა შეიცვალა Video DIAL მოთხოვნით."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS მოთხოვნა შეიცვალა USSD მოთხოვნით."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS მოთხოვნა შეიცვალა ახალი SS მოთხოვნით."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"სამსახურის პროფილი"</string>
@@ -1782,14 +1790,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..d56e6df 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"Сеансты аяқтау"</string>
<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 +1052,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 +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 Wi-Fi желісіне қосылғысы келеді"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Қолданба"</string>
@@ -1495,6 +1500,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Түстер инверсиясы"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Түс жөндеу"</string>
<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 +1633,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 +1641,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>
@@ -1682,13 +1688,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Ұйқы режимі"</string>
<string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> үнін өшірген"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"There\'s an internal problem with your device, and it may be unstable until you factory data reset."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"There\'s an internal problem with your device. Contact your manufacturer for details."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD сұрауы DIAL сұрауына өзгертілді."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD сұрауы SS сұрауына өзгертілді."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD сұрауы жаңа USSD сұрауына өзгертілді."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD сұрауы бейне DIAL сұрауына өзгертілді."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS сұрауы DIAL сұрауына өзгертілді."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS сұрауы бейне DIAL сұрауына өзгертілді."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS сұрауы USSD сұрауына өзгертілді."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS сұрауы жаңа SS сұрауына өзгертілді."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Жұмыс профилі"</string>
@@ -1782,14 +1791,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..b2778a1 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"បញ្ចប់សម័យ"</string>
<string name="bugreport_title" msgid="2667494803742548533">"យករបាយការណ៍កំហុស"</string>
<string name="bugreport_message" msgid="398447048750350456">"វានឹងប្រមូលព័ត៌មានអំពីស្ថានភាពឧបករណ៍របស់អ្នក ដើម្បីផ្ញើជាសារអ៊ីមែល។ វានឹងចំណាយពេលតិចពីពេលចាប់ផ្ដើមរបាយការណ៍រហូតដល់ពេលវារួចរាល់ដើម្បីផ្ញើ សូមអត់ធ្មត់។"</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"របាយការណ៍អន្តរកម្ម"</string>
@@ -1053,6 +1054,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 +1122,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 +1136,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>
@@ -1497,6 +1501,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"បញ្ច្រាសពណ៌"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"ការកែពណ៌"</string>
<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>
@@ -1628,7 +1634,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 +1642,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>
@@ -1684,13 +1689,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"កំពុងដេក"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"សំណើរ USSD ត្រូវបានកែសម្រួលទៅតាមសំណើរការហៅទូរស័ព្ទ។"</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"សំណើរ USSD ត្រូវបានកែសម្រួលទៅតាមសំណើរ SS។"</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"សំណើរ USSD ត្រូវបានកែសម្រួលទៅតាមសំណើរ USSD ថ្មី។្"</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"សំណើ USSD ត្រូវបានកែសម្រួលទៅជាសំណើ Video DIAL ។"</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"សំណើរ SS ត្រូវបានកែសម្រួលទៅតាមសំណើរការហៅទូរស័ព្ទ។"</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"សំណើ SS ត្រូវបានកែសម្រួលទៅជាសំណើ Video DIAL ។"</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"សំណើរ SS ត្រូវបានកែសម្រួលទៅតាមសំណើរ USSD។"</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"សំណើរ SS ត្រូវបានកែសម្រួលទៅតាមសំណើរ SS ថ្មី។"</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"ប្រវត្តិរូបការងារ"</string>
@@ -1784,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-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 609bef0..4485561 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"ಸೆಷನ್ ಅಂತ್ಯಗೊಳಿಸಿ"</string>
<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 +1052,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 +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">"%2$s ವೈಫೈ ನೆಟ್ವರ್ಕ್ಗೆ ಸಂಪರ್ಕಿಸಲು %1$s ಅಪ್ಲಿಕೇಶನ್ ಬಯಸುತ್ತದೆ"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"ಅಪ್ಲಿಕೇಶನ್"</string>
@@ -1495,6 +1500,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"ಬಣ್ಣ ವಿಲೋಮ"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"ಬಣ್ಣ ತಿದ್ದುಪಡಿ"</string>
<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>
@@ -1634,7 +1641,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>
@@ -1681,13 +1688,18 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"ಮಲಗುತ್ತಿದ್ದಾರೆ"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD ವಿನಂತಿಯನ್ನು DIAL ವಿನಂತಿಗೆ ಮಾರ್ಪಡಿಸಲಾಗಿದೆ."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD ವಿನಂತಿಯನ್ನು SS ವಿನಂತಿಗೆ ಮಾರ್ಪಡಿಸಲಾಗಿದೆ."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD ವಿನಂತಿಯನ್ನು ಹೊಸ USSD ವಿನಂತಿಗೆ ಮಾರ್ಪಡಿಸಲಾಗಿದೆ."</string>
+ <!-- no translation found for stk_cc_ussd_to_dial_video (585340552561515305) -->
+ <skip />
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS ವಿನಂತಿಯನ್ನು DIAL ವಿನಂತಿಗೆ ಮಾರ್ಪಡಿಸಲಾಗಿದೆ."</string>
+ <!-- no translation found for stk_cc_ss_to_dial_video (4306210904450719045) -->
+ <skip />
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS ವಿನಂತಿಯನ್ನು USSD ವಿನಂತಿಗೆ ಮಾರ್ಪಡಿಸಲಾಗಿದೆ."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS ವಿನಂತಿಯನ್ನು ಹೊಸ SS ವಿನಂತಿಗೆ ಮಾರ್ಪಡಿಸಲಾಗಿದೆ."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 1976bbe..650d980 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"세션 끝내기"</string>
<string name="bugreport_title" msgid="2667494803742548533">"버그 신고"</string>
<string name="bugreport_message" msgid="398447048750350456">"현재 기기 상태에 대한 정보를 수집하여 이메일 메시지로 전송합니다. 버그 신고를 시작하여 전송할 준비가 되려면 약간 시간이 걸립니다."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"대화형 보고서"</string>
@@ -867,7 +868,7 @@
<item quantity="other">지난 <xliff:g id="COUNT_1">%d</xliff:g>일</item>
<item quantity="one">지난 <xliff:g id="COUNT_0">%d</xliff:g>일</item>
</plurals>
- <string name="last_month" msgid="3959346739979055432">"지난 달"</string>
+ <string name="last_month" msgid="3959346739979055432">"지난달"</string>
<string name="older" msgid="5211975022815554840">"이전"</string>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
@@ -1051,6 +1052,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 +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,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>
@@ -1495,6 +1499,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"색상 반전"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"색상 보정"</string>
<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>
@@ -1634,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>
@@ -1681,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"수면 중"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD 요청이 DIAL 요청으로 수정됩니다."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD 요청이 SS 요청으로 수정됩니다."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD 요청이 새로운 USSD 요청으로 수정됩니다."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD 요청이 동영상 DIAL 요청으로 수정됩니다."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS 요청이 DIAL 요청으로 수정됩니다."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS 요청이 동영상 DIAL 요청으로 수정됩니다."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS 요청이 USSD 요청으로 수정됩니다."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS 요청이 새로운 SS 요청으로 수정됩니다."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"직장 프로필"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index a1cc479..e580a59 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"Сессияны аяктоо"</string>
<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 +1052,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 +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>
@@ -1496,6 +1501,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Түстү инверсиялоо"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Түстү түзөтүү"</string>
<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>
@@ -1627,7 +1634,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 +1642,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>
@@ -1683,13 +1689,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Уйку режими"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD сурамы DIAL сурамына өзгөртүлдү."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD сурамы SS сурамына өзгөртүлдү."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD сурамы жаңы USSD сурамына өзгөртүлдү."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD сурамы Видео DIAL сурамына өзгөртүлдү."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS сурамы DIAL сурамына өзгөртүлдү."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS сурамы Видео DIAL сурамына өзгөртүлдү."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS сурамы USSD сурамына өзгөртүлдү."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS сурамы жаңы SS сурамына өзгөртүлдү."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Жумуш профили"</string>
@@ -1783,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-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 79a41aa..feedbf3 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"ສິ້ນສຸດເຊດຊັນ"</string>
<string name="bugreport_title" msgid="2667494803742548533">"ໃຊ້ລາຍງານຂໍ້ບົກພ່ອງ"</string>
<string name="bugreport_message" msgid="398447048750350456">"ນີ້ຈະເປັນການເກັບກຳຂໍ້ມູນກ່ຽວກັບ ສະຖານະປັດຈຸບັນຂອງອຸປະກອນທ່ານ ເພື່ອສົ່ງເປັນຂໍ້ຄວາມທາງອີເມວ. ມັນຈະໃຊ້ເວລາໜ້ອຍນຶ່ງ ໃນການເລີ່ມຕົ້ນການລາຍງານຂໍ້ຜິດພາດ ຈົນກວ່າຈະພ້ອມທີ່ຈະສົ່ງໄດ້, ກະລຸນາລໍຖ້າ."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"ລາຍງານແບບໂຕ້ຕອບ"</string>
@@ -263,7 +264,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 +980,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 +994,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 +1050,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 +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="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 +1134,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>
@@ -1503,6 +1499,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"ການປີ້ນສີ"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"ການແກ້ໄຂຄ່າສີ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ເລືອກຄຸນສົມບັດທີ່ຈະໃຊ້ເມື່ອທ່ານແຕະປຸ່ມການຊ່ວຍເຂົ້າເຖິງ:"</string>
@@ -1634,7 +1632,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 +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>
@@ -1690,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"ການນອນ"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"ການຂໍ USSD ຖືກດັດແປງເປັນການຂໍ DIAL ແລ້ວ."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"ການຂໍ USSD ຖືກດັດແປງເປັນການຂໍ SS ແລ້ວ."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"ການຂໍ USSD ຖືກດັດແປງເປັນການຂໍ USSD ໃໝ່ແລ້ວ."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"ການຂໍ USSD ຖືກດັດແປງເປັນການຂໍ DIAL ວິດີໂອແລ້ວ."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"ການຂໍ SS ຖືກດັດແປງເປັນການຂໍ DIAL ແລ້ວ."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"ການຂໍ SS ຖືກດັດແປງເປັນການຂໍ DIAL ວິດີໂອແລ້ວ."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"ການຂໍ SS ຖືກດັດແປງເປັນການຂໍ USSD ແລ້ວ."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"ການຂໍ SS ຖືກດັດແປງເປັນການຂໍ SS ໃໝ່ແລ້ວ."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string>
@@ -1790,18 +1790,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..95e4862 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>
@@ -216,6 +216,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Išjungiamas maitinimas"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Skambutis pagalbos numeriu"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Pranešimas apie riktą"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Baigti seansą"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Pranešti apie riktą"</string>
<string name="bugreport_message" msgid="398447048750350456">"Bus surinkta informacija apie dabartinę įrenginio būseną ir išsiųsta el. pašto pranešimu. Šiek tiek užtruks, kol pranešimas apie riktą bus paruoštas siųsti; būkite kantrūs."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interakt. ataskaita"</string>
@@ -1091,6 +1092,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 +1164,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 +1178,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>
@@ -1543,6 +1547,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Kai spartusis klavišas įjungtas, spaudžiant abu garsumo mygtukus 3 sekundes bus paleista pritaikymo neįgaliesiems funkcija.\n\n Dabartinė pritaikymo neįgaliesiems funkcija:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>„\n“\n Funkciją galite pakeisti skiltyje „Nustatymai“ > „Pritaikymas neįgaliesiems“."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Išjungti spartųjį klavišą"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Naudoti spartųjį klavišą"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Spalvų inversija"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Spalvų taisymas"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pritaikymo neįgaliesiems sparčiuoju klavišu buvo įjungta „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pritaikymo neįgaliesiems sparčiuoju klavišu buvo išjungta „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pasirinkite funkciją, kuri bus naudojama, kai paliesite pritaikymo neįgaliesiems mygtuką:"</string>
@@ -1676,7 +1682,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 +1690,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>
@@ -1748,13 +1753,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Darbo dienos vakarą"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Savaitgalį"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Įvykis"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Miegas"</string>
<string name="muted_by" msgid="6147073845094180001">"Nutildė <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Iškilo vidinė su jūsų įrenginiu susijusi problema, todėl įrenginys gali veikti nestabiliai, kol neatkursite gamyklinių duomenų."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Iškilo vidinė su jūsų įrenginiu susijusi problema. Jei reikia išsamios informacijos, susisiekite su gamintoju."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD užklausa pakeista į DIAL užklausą."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD užklausa pakeista į SS užklausą."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD užklausa pakeista į naują USSD užklausą."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD užklausa pakeista į „Video DIAL“ užklausą."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS užklausa pakeista į DIAL užklausą."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS užklausa pakeista į „Video DIAL“ užklausą."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS užklausa pakeista į USSD užklausą."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS užklausa pakeista į naują SS užklausą."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Darbo profilis"</string>
@@ -1852,14 +1860,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..12bb04b 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>
@@ -214,6 +214,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Strāvas padeve ir izslēgta."</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Ārkārtas"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Kļūdu ziņojums"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Beigt sesiju"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Kļūdu ziņojuma sagatavošana"</string>
<string name="bugreport_message" msgid="398447048750350456">"Veicot šo darbību, tiks apkopota informācija par jūsu ierīces pašreizējo stāvokli un nosūtīta e-pasta ziņojuma veidā. Kļūdu ziņojuma pabeigšanai un nosūtīšanai var būt nepieciešams laiks. Lūdzu, esiet pacietīgs."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktīvs pārskats"</string>
@@ -1071,6 +1072,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 +1142,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 +1156,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>
@@ -1519,6 +1523,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Ja saīsne ir iespējota, vienlaikus nospiežot abas skaļuma regulēšanas pogas un trīs sekundes turot tās, tiks palaista pieejamības funkcija.\n\n Pašreiz iestatītā pieejamības funkcija:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Šo funkciju var mainīt sadaļā Iestatījumi > Pieejamība."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Izslēgt saīsni"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Izmantot saīsni"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Krāsu inversija"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Krāsu korekcija"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pieejamības saīsne aktivizēja lietotni <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pieejamības saīsne deaktivizēja lietotni <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izvēlieties funkciju, ko izmantot, kad pieskaraties pogai Pieejamība."</string>
@@ -1651,7 +1657,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 +1665,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>
@@ -1715,13 +1720,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Darbadienas vakarā"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Nedēļas nogalē"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Pasākums"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Gulēšana"</string>
<string name="muted_by" msgid="6147073845094180001">"Skaņu izslēdza <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Jūsu ierīcē ir radusies iekšēja problēma, un ierīce var darboties nestabili. Lai to labotu, veiciet rūpnīcas datu atiestatīšanu."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Jūsu ierīcē ir radusies iekšēja problēma. Lai iegūtu plašāku informāciju, lūdzu, sazinieties ar ražotāju."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD pieprasījums ir mainīts uz DIAL pieprasījumu."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD pieprasījums ir mainīts uz SS pieprasījumu."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD pieprasījums ir mainīts uz jaunu USSD pieprasījumu."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD pieprasījums ir mainīts uz Video DIAL pieprasījumu."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS pieprasījums ir mainīts uz DIAL pieprasījumu."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS pieprasījums ir mainīts uz Video DIAL pieprasījumu."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS pieprasījums ir mainīts uz USSD pieprasījumu."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS pieprasījums ir mainīts uz jaunu SS pieprasījumu."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Darba profils"</string>
@@ -1817,14 +1825,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..c5773f8 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"Завршете ја сесијата"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Земи извештај за грешки"</string>
<string name="bugreport_message" msgid="398447048750350456">"Ова ќе собира информации за моменталната состојба на вашиот уред, за да ги испрати како порака по е-пошта. Тоа ќе одземе малку време почнувајќи од извештајот за грешки додека не се подготви за праќање; бидете трпеливи."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Интерактивен извештај"</string>
@@ -984,7 +985,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 +1052,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 +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="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 +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>
@@ -1497,6 +1502,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Инверзија на бои"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Корекција на бои"</string>
<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>
@@ -1628,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">"Прашај за PIN пред откачување"</string>
@@ -1637,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>
@@ -1684,13 +1690,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Спиење"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Барањето USSD е изменето во барање DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Барањето USSD е изменето во барање SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Барањето USSD е изменето во ново барање USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Барањето USSD е изменето во барање видео DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Барањето SS е изменето во барање DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Барањето SS е изменето во барање видео DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Барањето SS е изменето во барање USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Барањето SS е изменето во ново барање SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Работен профил"</string>
@@ -1784,14 +1793,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..2595f94 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"സെഷൻ അവസാനിപ്പിക്കുക"</string>
<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 +1052,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 +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">"വൈഫൈയ്ക്ക് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ല"</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>
@@ -1495,6 +1500,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"വർണ്ണ വിപര്യയം"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"വർണ്ണം ക്രമീകരിക്കൽ"</string>
<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>
@@ -1634,7 +1641,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>
@@ -1681,13 +1688,18 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"ഉറക്കം"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD അഭ്യർത്ഥന, DIAL അഭ്യർത്ഥനയായി പരിഷ്ക്കരിച്ചു."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD അഭ്യർത്ഥന, SS അഭ്യർത്ഥനയായി പരിഷ്ക്കരിച്ചു."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD അഭ്യർത്ഥന, പുതിയ USSD അഭ്യർത്ഥനയായി പരിഷ്ക്കരിച്ചു."</string>
+ <!-- no translation found for stk_cc_ussd_to_dial_video (585340552561515305) -->
+ <skip />
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS അഭ്യർത്ഥന, DIAL അഭ്യർത്ഥനയായി പരിഷ്ക്കരിച്ചു."</string>
+ <!-- no translation found for stk_cc_ss_to_dial_video (4306210904450719045) -->
+ <skip />
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS അഭ്യർത്ഥന, USSD അഭ്യർത്ഥനയായി പരിഷ്ക്കരിച്ചു."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS അഭ്യർത്ഥന, പുതിയ SS അഭ്യർത്ഥനയായി പരിഷ്ക്കരിച്ചു."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 3e1992b..9f26a3b 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"Гаргах харилцан үйлдэл"</string>
<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 +1052,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 +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,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 +1499,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Өнгө хувиргалт"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Өнгөний засвар"</string>
<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 +1632,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 +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>
@@ -1680,13 +1685,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Идэвхгүй"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD хүсэлтийг DIAL хүсэлт болгон өөрчилсөн байна."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD хүсэлтийг SS хүсэлт болгон өөрчилсөн байна."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD хүсэлтийг шинэ USSD хүсэлт болгон өөрчилсөн байна."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD хүсэлтийг Видео DIAL хүсэлт болгон өөрчилсөн байна."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS хүсэлтийг DIAL хүсэлт болгон өөрчилсөн байна"</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS хүсэлтийг Видео DIAL хүсэлт болгон өөрчилсөн байна."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS хүсэлтийг USSD хүсэлт болгон өөрчилсөн байна."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS хүсэлтийг шинэ SS хүсэлт болгон өөрчилсөн байна."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Ажлын профайл"</string>
@@ -1780,14 +1788,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..a757849 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>
@@ -145,7 +144,7 @@
<string name="httpErrorAuth" msgid="1435065629438044534">"प्रमाणीकृत करू शकलो नाही."</string>
<string name="httpErrorProxyAuth" msgid="1788207010559081331">"प्रॉक्सी सर्व्हरद्वारे प्रमाणीकरण यशस्वी झाले."</string>
<string name="httpErrorConnect" msgid="8714273236364640549">"सर्व्हरशी कनेक्ट करू शकलो नाही."</string>
- <string name="httpErrorIO" msgid="2340558197489302188">"या सर्व्हरशी संप्रेषण करू शकलो नाही. नंतर पुन्हा प्रयत्न करा."</string>
+ <string name="httpErrorIO" msgid="2340558197489302188">"या सर्व्हरशी संवाद प्रस्थापित करू शकलो नाही. नंतर पुन्हा प्रयत्न करा."</string>
<string name="httpErrorTimeout" msgid="4743403703762883954">"सर्व्हरवरील कनेक्शन टाइमआउट झाले."</string>
<string name="httpErrorRedirectLoop" msgid="8679596090392779516">"पृष्ठामध्ये बरीच सर्व्हर पुनर्निर्देशने आहेत."</string>
<string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"प्रोटोकॉल समर्थित नाही."</string>
@@ -213,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"सेशन समाप्त करा"</string>
<string name="bugreport_title" msgid="2667494803742548533">"बग रीपोर्ट घ्या"</string>
<string name="bugreport_message" msgid="398447048750350456">"ई-मेल संदेश म्हणून पाठविण्यासाठी, हे तुमच्या सद्य डिव्हाइस स्थितीविषयी माहिती संकलित करेल. बग रीपोर्ट सुरू करण्यापासून तो पाठविण्यापर्यंत थोडा वेळ लागेल; कृपया धीर धरा."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"परस्परसंवादी अहवाल"</string>
@@ -362,13 +362,13 @@
<string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"रोचक प्रसारणे पाठविण्यास अॅपला अनुमती देते, जे प्रसारण समाप्त झाल्यानंतर तसेच रहाते. अतिरिक्त वापर टीव्ही धीमा किंवा यासाठी बरीच मेमरी वापरली जात असल्यामुळे तो अस्थिर करू शकतो."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"रोचक प्रसारणे पाठविण्यासाठी अॅप ला अनुमती देते, जे प्रसारण समाप्त झाल्यानंतर देखील तसेच राहते. अत्याधिक वापरामुळे बरीच मेमरी वापरली जाऊन तो फोनला धीमा किंवा अस्थिर करू शकतो."</string>
<string name="permlab_readContacts" msgid="8348481131899886131">"आपले संपर्क वाचा"</string>
- <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"आपण कॉल केलेल्या, ईमेल केलेल्या किंवा विशिष्ट लोकांशी अन्य मार्गांनी संप्रेषण केलेल्या लोकांच्या फ्रिक्वेन्सीसह, आपल्या टॅब्लेटवर संचयित केलेल्या आपल्या संपर्कांविषयीचा डेटा वाचण्यासाठी अॅप ला अनुमती देते. ही परवानगी आपला संपर्क डेटा जतन करण्याची अॅप्स ला अनुमती देते आणि दुर्भावनापूर्ण अॅप्स आपल्या माहितीशिवाय संपर्क डेटा सामायिक करू शकतात."</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"आपण कॉल केलेल्या, ईमेल केलेल्या किंवा विशिष्ट लोकांशी अन्य मार्गांनी संवाद प्रस्थापित केलेल्या लोकांच्या फ्रिक्वेन्सीसह, आपल्या टॅब्लेटवर संचयित केलेल्या आपल्या संपर्कांविषयीचा डेटा वाचण्यासाठी अॅप ला अनुमती देते. ही परवानगी आपला संपर्क डेटा जतन करण्याची अॅप्स ला अनुमती देते आणि दुर्भावनापूर्ण अॅप्स आपल्या माहितीशिवाय संपर्क डेटा सामायिक करू शकतात."</string>
<string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"आपण विशिष्ट लोकांना इतर मार्गांनी कॉल केलेल्या, ईमेल केलेल्या किंवा संप्रेषित केलेल्या फ्रिक्वेन्सीसह, आपल्या टीव्हीवर संचयित केलेल्या आपल्या संपर्कांविषयीचा डेटा वाचण्यासाठी अॅप्सला अनुमती देतात. ही परवागनी अॅप्सला आपला संपर्क डेटा जतन करण्यासाठी अनुमती देते आणि दुर्भावनापूर्ण अॅप्स आपल्याला न कळविता संपर्क डेटा सामायिक करू शकतात."</string>
- <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"आपण कॉल केलेल्या, ईमेल केलेल्या किंवा विशिष्ट लोकांशी अन्य मार्गांनी संप्रेषण केलेल्या लोकांच्या फ्रिक्वेन्सीसह, आपल्या फोनवर संचयित केलेल्या आपल्या संपर्कांविषयीचा डेटा वाचण्यासाठी अॅप ला अनुमती देते. ही परवानगी आपला संपर्क डेटा जतन करण्याची अॅप्स ला अनुमती देते आणि दुर्भावनापूर्ण अॅप्स आपल्या माहितीशिवाय संपर्क डेटा सामायिक करू शकतात."</string>
+ <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"आपण कॉल केलेल्या, ईमेल केलेल्या किंवा विशिष्ट लोकांशी अन्य मार्गांनी संवाद प्रस्थापित केलेल्या लोकांच्या फ्रिक्वेन्सीसह, आपल्या फोनवर संचयित केलेल्या आपल्या संपर्कांविषयीचा डेटा वाचण्यासाठी अॅप ला अनुमती देते. ही परवानगी आपला संपर्क डेटा जतन करण्याची अॅप्स ला अनुमती देते आणि दुर्भावनापूर्ण अॅप्स आपल्या माहितीशिवाय संपर्क डेटा सामायिक करू शकतात."</string>
<string name="permlab_writeContacts" msgid="5107492086416793544">"आपले संपर्क सुधारित करा"</string>
- <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"आपण विशिष्ट संपर्कांशी अन्य मार्गांनी कॉल केलेल्या, ईमेल केलेल्या किंवा संप्रेषण केलेल्या फ्रिक्वेन्सीसह, आपल्या टॅब्लेटवर संचयित केलेल्या आपल्या संपर्कांविषयीचा डेटा सुधारित करण्यासाठी अॅप ला अनुमती देते. ही परवानगी संपर्क डेटा हटविण्यासाठी अॅप ला अनुमती देते."</string>
- <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"आपण विशिष्ट संपर्कांशी अन्य मार्गांनी कॉल केलेल्या, ईमेल केलेल्या किंवा संप्रेषण केलेल्या फ्रिक्वेन्सीसह, आपल्या टीव्हीवर संचयित केलेल्या आपल्या संपर्कांविषयीचा डेटा सुधारित करण्यासाठी अॅपला अनुमती देते. ही परवानगी संपर्क डेटा हटविण्यासाठी अॅपला अनुमती देते."</string>
- <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"आपण विशिष्ट संपर्कांशी अन्य मार्गांनी कॉल केलेल्या, ईमेल केलेल्या किंवा संप्रेषण केलेल्या फ्रिक्वेन्सीसह, आपल्या फोनवर संचयित केलेल्या आपल्या संपर्कांविषयीचा डेटा सुधारित करण्यासाठी अॅप ला अनुमती देते. ही परवानगी संपर्क डेटा हटविण्यासाठी अॅप ला अनुमती देते."</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"आपण विशिष्ट संपर्कांशी अन्य मार्गांनी कॉल केलेल्या, ईमेल केलेल्या किंवा संवाद प्रस्थापित केलेल्या फ्रिक्वेन्सीसह, आपल्या टॅब्लेटवर संचयित केलेल्या आपल्या संपर्कांविषयीचा डेटा सुधारित करण्यासाठी अॅप ला अनुमती देते. ही परवानगी संपर्क डेटा हटविण्यासाठी अॅप ला अनुमती देते."</string>
+ <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"आपण विशिष्ट संपर्कांशी अन्य मार्गांनी कॉल केलेल्या, ईमेल केलेल्या किंवा संवाद प्रस्थापित केलेल्या फ्रिक्वेन्सीसह, आपल्या टीव्हीवर संचयित केलेल्या आपल्या संपर्कांविषयीचा डेटा सुधारित करण्यासाठी अॅपला अनुमती देते. ही परवानगी संपर्क डेटा हटविण्यासाठी अॅपला अनुमती देते."</string>
+ <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"आपण विशिष्ट संपर्कांशी अन्य मार्गांनी कॉल केलेल्या, ईमेल केलेल्या किंवा संवाद प्रस्थापित केलेल्या फ्रिक्वेन्सीसह, आपल्या फोनवर संचयित केलेल्या आपल्या संपर्कांविषयीचा डेटा सुधारित करण्यासाठी अॅप ला अनुमती देते. ही परवानगी संपर्क डेटा हटविण्यासाठी अॅप ला अनुमती देते."</string>
<string name="permlab_readCallLog" msgid="3478133184624102739">"कॉल लॉग वाचा"</string>
<string name="permdesc_readCallLog" msgid="3204122446463552146">"हा अॅप आपला कॉल इतिहास वाचू शकता."</string>
<string name="permlab_writeCallLog" msgid="8552045664743499354">"कॉल लॉग लिहा"</string>
@@ -1052,12 +1052,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>
- <!-- 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 +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>
@@ -1505,6 +1500,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"रंगांची उलटापालट"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"रंग सुधारणा"</string>
<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 +1641,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,13 +1688,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"झोपलेले आहे"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD विनंती डायल विनंतीवर सुधारित केली आहे."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD विनंती SS विनंतीवर सुधारित केली आहे."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD विनंती नवीन USSD विनंतीवर सुधारित केली आहे."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD विनंतीमध्ये बदल करून ती व्हिडिओ डायल विनंतीमध्ये बदलली आहे."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS विनंती डायल विनंतीवर सुधारित केली आहे."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS विनंतीमध्ये बदल करून ती व्हिडिओ डायल विनंतीमध्ये बदलली आहे."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS विनंती USSD विनंतीवर सुधारित केली आहे."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS विनंती नवीन SS विनंतीवर सुधारित केली आहे."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"कार्य प्रोफाईल"</string>
@@ -1753,7 +1753,7 @@
<string name="app_category_audio" msgid="1659853108734301647">"संगीत आणि ऑडिओ"</string>
<string name="app_category_video" msgid="2728726078629384196">"चित्रपट आणि व्हिडिओ"</string>
<string name="app_category_image" msgid="4867854544519846048">"फोटो आणि इमेज"</string>
- <string name="app_category_social" msgid="5842783057834965912">"सामाजिक आणि संप्रेषण"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"सामाजिक आणि संवाद प्रस्थापित"</string>
<string name="app_category_news" msgid="7496506240743986873">"बातम्या आणि मासिके"</string>
<string name="app_category_maps" msgid="5878491404538024367">"नकाशे आणि नेव्हिगेशन"</string>
<string name="app_category_productivity" msgid="3742083261781538852">"उत्पादनक्षमता"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 3753fb2..aee2000 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Matikan kuasa"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Kecemasan"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Laporan pepijat"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Tamatkan sesi"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Ambil laporan pepijat"</string>
<string name="bugreport_message" msgid="398447048750350456">"Ini akan mengumpul maklumat tentang keadaan peranti semasa anda untuk dihantarkan sebagai mesej e-mel. Harap bersabar, mungkin perlu sedikit masa untuk memulakan laporan sehingga siap untuk dihantar."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Laporan interaktif"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Apabila pintasan dihidupkan, tindakan menekan kedua-dua butang kelantangan selama 3 saat akan memulakan ciri kebolehaksesan.\n\n Ciri kebolehaksesan semasa:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Anda boleh menukar ciri itu dalam Tetapan > Kebolehaksesan."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Matikan pintasan"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Gunakan Pintasan"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Penyongsangan Warna"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Pembetulan Warna"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pintasan kebolehaksesan menghidupkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pintasan Kebolehaksesan mematikan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pilih ciri yang hendak digunakan apabila anda mengetik butang Kebolehaksesan:"</string>
@@ -1626,7 +1632,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 +1640,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>
@@ -1682,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Malam selain hujung minggu"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Hujung minggu"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Acara"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Tidur"</string>
<string name="muted_by" msgid="6147073845094180001">"Diredam oleh <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Terdapat masalah dalaman dengan peranti anda. Peranti mungkin tidak stabil sehingga anda membuat tetapan semula data kilang."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Terdapat masalah dalaman dengan peranti anda. Hubungi pengilang untuk mengetahui butirannya."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Permintaan USSD diubah kepada permintaan DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Permintaan USSD diubah kepada permintaan SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Permintaan USSD diubah kepada permintaan USSD baharu."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Permintaan USSD diubah suai kepada permintaan DAIL Video."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Permintaan SS diubah kepada permintaan DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Permintaan SS diubah suai kepada permintaan DAIL Video."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Permintaan SS diubah kepada permintaan USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Permintaan SS diubah kepada permintaan SS baharu."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profil kerja"</string>
@@ -1782,14 +1790,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..fec37ab 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"သတ်မှတ်ပေးထားသည့်အချိန် ပြီးဆုံးပြီ"</string>
<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 +1052,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 +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">"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">"ဝိုင်ဖိုင်ကိုချိတ်ဆက်မရပါ"</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>
@@ -1495,6 +1500,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"အရောင် ပြောင်းပြန်လှန်ခြင်း"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"အရောင်ပြင်ဆင်ခြင်း"</string>
<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 +1633,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 +1641,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,13 +1688,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"အိပ်နေချိန်"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"DIAL တောင်းဆိုချက်အရ USSD တောင်းဆိုချက်အား ပြင်ဆင်ထား၏။"</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"SS တောင်းဆိုချက် အရ USSD တောင်းဆိုချက်အား ပြင်ဆင်ထား၏။"</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD တောင်းဆိုချက် အသစ်အရ USSD တောင်းဆိုချက်အား ပြင်ဆင်ထား၏။"</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD တောင်းဆိုချက်အား Video DIAL တောင်းဆိုချက်သို့ ပြုပြင်ထားသည်။"</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"DIAL တောင်းဆိုချက်အရ SS တောင်းဆိုချက်အား ပြင်ဆင်ထား၏။"</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS တောင်းဆိုချက်အား Video DIAL တောင်းဆိုချက်သို့ ပြုပြင်ထားသည်။"</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"USSD တောင်းဆိုချက်အရ SS တောင်းဆိုချက်အား ပြင်ဆင်ထား၏။"</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS တောင်းဆိုချက်အရ SS တောင်းဆိုချက်အား ပြင်ဆင်ထား၏။"</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"အလုပ်ကိုယ်ရေးအချက်အလက်"</string>
@@ -1782,14 +1791,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..915701c 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Slå av"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Nødsituasjon"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Feilrapport"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Avslutt økten"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Utfør feilrapport"</string>
<string name="bugreport_message" msgid="398447048750350456">"Informasjon om tilstanden til enheten din samles inn og sendes som en e-post. Det tar litt tid fra du starter feilrapporten til e-posten er klar, så vær tålmodig."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiv rapport"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Når snarveien er på, starter en tilgjengelighetsfunksjon når du trykker inn begge volumknappene i tre sekunder.\n\n Nåværende tilgjengelighetsfunksjon:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kan endre funksjonen i Innstillinger > Tilgjengelighet."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Slå av snarveien"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Bruk snarveien"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Fargeinvertering"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Fargekorrigering"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Snarveien for tilgjengelighet slo på <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Snarveien for tilgjengelighet slo av <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Velg en funksjon du vil bruke når du trykker på Tilgjengelighet-knappen:"</string>
@@ -1626,7 +1632,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 +1640,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>
@@ -1682,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Hverdagskveld"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Helg"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Aktivitet"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Sover"</string>
<string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> har kuttet lyden"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Det har oppstått et internt problem på enheten din, og den kan være ustabil til du tilbakestiller den til fabrikkdata."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Det har oppstått et internt problem på enheten din. Ta kontakt med produsenten for mer informasjon."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD-forespørselen er endret til en RINGE-forespørsel."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD-forespørselen er endret til en SS-forespørsel."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD-forespørsel er endret til en ny USSD-forespørsel."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD-forespørselen er endret til en RINGE-forespørsel med video."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-forespørselen er endret til en RINGE-forespørsel."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS-forespørselen er endret til en RINGE-forespørsel med video."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-forespørselen er endret til en USSD-forespørsel."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-forespørselen er endret til en ny SS-forespørsel."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Arbeidsprofil"</string>
@@ -1782,14 +1790,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..9223c76 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"सत्रको अन्त्य गर्नुहोस्"</string>
<string name="bugreport_title" msgid="2667494803742548533">"बग रिपोर्ट लिनुहोस्"</string>
<string name="bugreport_message" msgid="398447048750350456">"एउटा इमेल सन्देशको रूपमा पठाउनलाई यसले तपाईँको हालैको उपकरणको अवस्थाको बारेमा सूचना जम्मा गर्ने छ। बग रिपोर्ट सुरु गरेदेखि पठाउन तयार नभएसम्म यसले केही समय लिन्छ; कृपया धैर्य गर्नुहोस्।"</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"अन्तरक्रियामूलक रिपोर्ट"</string>
@@ -1057,6 +1058,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 +1126,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 +1140,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>
@@ -1501,6 +1505,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"रङ्ग उल्टाउने सुविधा"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"रङ सच्याउने सुविधा"</string>
<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>
@@ -1640,7 +1646,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>
@@ -1687,13 +1693,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"शयन अवस्था"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD अनुरोध DIAL अनुरोधमा परिमार्जन गरिएको छ।"</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD अनुरोध SS अनुरोधमा परिमार्जन गरिएको छ।"</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD अनुरोध नयाँ USSD अनुरोधमा परिमार्जन गरिएको छ।"</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD अनुरोधलाई भिडियो DIAL अनुरोधमा परिमार्जन गरियो।"</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS अनुरोध DIAL अनुरोधमा परिमार्जन गरिएको छ।"</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS अनुरोधलाई भिडियो DIAL अनुरोधमा परिमार्जन गरियो।"</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS अनुरोध USSD अनुरोधमा परिमार्जन गरिएको छ।"</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS अनुरोध नयाँ SS अनुरोधमा परिमार्जन गरिएको छ।"</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"कार्य प्रोफाइल"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index f99d531..5ae838e 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Uitschakelen"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Noodgeval"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Bugrapport"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Sessie beëindigen"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Bugrapport genereren"</string>
<string name="bugreport_message" msgid="398447048750350456">"Hiermee worden gegevens over de huidige status van je apparaat verzameld en als e-mail verzonden. Wanneer u een bugrapport start, duurt het even voordat het kan worden verzonden. Even geduld alstublieft."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interactief rapport"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Wanneer de snelkoppeling is ingeschakeld, kun je drie seconden op beide volumeknoppen drukken om een toegankelijkheidsfunctie te starten.\n\n Huidige toegankelijkheidsfunctie:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Je kunt de functie wijzigen in Instellingen > Toegankelijkheid."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Sneltoets uitschakelen"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Sneltoets gebruiken"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Kleurinversie"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Kleurcorrectie"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"\'Snelle link voor toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ingeschakeld"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"\'Snelle link voor toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> uitgeschakeld"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Kies een functie om te gebruiken wanneer je op de knop Toegankelijkheid tikt:"</string>
@@ -1634,7 +1640,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>
@@ -1681,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Doordeweekse avond"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Weekend"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Evenement"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Slapen"</string>
<string name="muted_by" msgid="6147073845094180001">"Gedempt door <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Er is een intern probleem met je apparaat. Het apparaat kan instabiel zijn totdat u het apparaat terugzet naar de fabrieksinstellingen."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Er is een intern probleem met je apparaat. Neem contact op met de fabrikant voor meer informatie."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD-verzoek is gewijzigd in DIAL-verzoek."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD-verzoek is gewijzigd in SS-verzoek."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD-verzoek is gewijzigd in nieuw USSD-verzoek."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD-verzoek is gewijzigd in Video DIAL-verzoek."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-verzoek is gewijzigd in DIAL-verzoek."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS-verzoek is gewijzigd in Video DIAL-verzoek."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-verzoek is gewijzigd in USSD-verzoek."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-verzoek is gewijzigd in nieuw SS-verzoek."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Werkprofiel"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index d269fac..283701e 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"ਸੈਸ਼ਨ ਸਮਾਪਤ ਕਰੋ"</string>
<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 +1052,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">"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>
@@ -1495,6 +1500,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"ਰੰਗ ਦੀ ਉਲਟੀ ਤਰਤੀਬ"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"ਰੰਗ ਸੁਧਾਈ"</string>
<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>
@@ -1634,7 +1641,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>
@@ -1681,13 +1688,18 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"ਸੌਣ ਵੇਲੇ"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD ਬੇਨਤੀ DIAL ਬੇਨਤੀ ਵਿੱਚ ਸੰਸ਼ੋਧਿਤ ਕੀਤੀ ਗਈ ਹੈ।"</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD ਬੇਨਤੀ SS ਬੇਨਤੀ ਵਿੱਚ ਸੰਸ਼ੋਧਿਤ ਕੀਤੀ ਗਈ ਹੈ।"</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD ਬੇਨਤੀ ਨਵੀਂ USSD ਬੇਨਤੀ ਵਿੱਚ ਸੰਸ਼ੋਧਿਤ ਕੀਤੀ ਗਈ ਹੈ।"</string>
+ <!-- no translation found for stk_cc_ussd_to_dial_video (585340552561515305) -->
+ <skip />
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS ਬੇਨਤੀ DIAL ਬੇਨਤੀ ਵਿੱਚ ਸੰਸ਼ੋਧਿਤ ਕੀਤੀ ਗਈ ਹੈ।"</string>
+ <!-- no translation found for stk_cc_ss_to_dial_video (4306210904450719045) -->
+ <skip />
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS ਬੇਨਤੀ USSD ਬੇਨਤੀ ਵਿੱਚ ਸੰਸ਼ੋਧਿਤ ਕੀਤੀ ਗਈ ਹੈ।"</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS ਬੇਨਤੀ ਨਵੀਂ SS ਵਿੱਚ ਸੰਸ਼ੋਧਿਤ ਕੀਤੀ ਗਈ ਹੈ।"</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index d7c10ec..77d706a 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>
@@ -216,6 +216,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Wyłącz"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Alarmowy"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Zgłoszenie błędu"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Zakończ sesję"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Zgłoś błąd"</string>
<string name="bugreport_message" msgid="398447048750350456">"Informacje o bieżącym stanie urządzenia zostaną zebrane i wysłane e-mailem. Przygotowanie zgłoszenia błędu do wysłania chwilę potrwa, więc zachowaj cierpliwość."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Raport interaktywny"</string>
@@ -275,7 +276,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 +1092,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 +1164,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 +1178,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>
@@ -1543,6 +1547,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Gdy skrót jest włączony, jednoczesne naciśnięcie przez trzy sekundy obu klawiszy sterowania głośnością uruchomi funkcję ułatwień dostępu.\n\nBieżąca funkcja ułatwień dostępu:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nFunkcję możesz zmienić, wybierając Ustawienia > Ułatwienia dostępu."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Wyłącz skrót"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Użyj skrótu"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inwersja kolorów"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcja kolorów"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Skrót ułatwień dostępu wyłączył usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Skrót ułatwień dostępu wyłączył usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Wybierz funkcję używaną po kliknięciu przycisku ułatwień dostępu."</string>
@@ -1684,7 +1690,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>
@@ -1747,13 +1753,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Noc poza weekendem"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Weekend"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Wydarzenie"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Sen"</string>
<string name="muted_by" msgid="6147073845094180001">"Ściszone przez: <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"W Twoim urządzeniu wystąpił problem wewnętrzny. Może być ono niestabilne, dopóki nie przywrócisz danych fabrycznych."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"W Twoim urządzeniu wystąpił problem wewnętrzny. Skontaktuj się z jego producentem, by otrzymać szczegółowe informacje."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Żądanie USSD zostało zmienione na żądanie DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Żądanie USSD zostało zmienione na żądanie SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Żądanie USSD zostało zmienione na nowe żądanie USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Żądanie USSD zostało zmienione na żądanie Video DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Żądanie SS zostało zmienione na żądanie DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Żądanie SS zostało zmienione na żądanie Video DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Żądanie SS zostało zmienione na żądanie USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Żądanie SS zostało zmienione na nowe żądanie SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profil do pracy"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 03c4536a..cce4bf0 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>
@@ -212,6 +212,7 @@
<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 bugs"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Finalizar sessão"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Obter relatório de bugs"</string>
<string name="bugreport_message" msgid="398447048750350456">"Isto coletará informações sobre o estado atual do dispositivo para enviá-las em uma mensagem de e-mail. Após iniciar o relatório de bugs, será necessário aguardar algum tempo até que esteja pronto para ser enviado."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Relatório interativo"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Quando o atalho está ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade.\n\n Recurso de acessibilidade atual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n É possível alterar o recurso em Configurações > Acessibilidade."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Desativar atalho"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Usar atalho"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inversão de cores"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Correção de cor"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atalho de acessibilidade ativou 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 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolha um recurso a ser usado ao tocar no botão Acessibilidade:"</string>
@@ -1634,7 +1640,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>
@@ -1681,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Durante a 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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Dormindo"</string>
<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">"Há um problema interno com seu dispositivo. Ele pode ficar instável até que você faça a redefinição para configuração original."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Há um problema interno com seu dispositivo. Entre em contato com o fabricante para saber mais detalhes."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"A solicitação USSD foi modificada para a solicitação DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"A solicitação USSD foi modificada para a solicitação SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"A solicitação USSD foi modificada para a nova solicitação USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"A solicitação USSD foi modificada para a solicitação DIAL de vídeo."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"A solicitação SS foi modificada para a solicitação DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"A solicitação SS foi modificada para a solicitação DIAL de vídeo."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"A solicitação SS foi modificada para a solicitação USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"A solicitação SS foi modificada para a nova solicitação SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Perfil de trabalho"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 2de83c6..434b50b 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,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"Terminar sessão"</string>
<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 +220,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 +865,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 +887,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 +1052,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 +1102,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 +1120,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 +1134,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 +1321,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 +1456,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 +1499,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inversão de cores"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Correção da cor"</string>
<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 +1613,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 +1640,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,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"A dormir"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"O pedido USSD foi modificado para um pedido DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"O pedido USSD foi modificado para um pedido SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"O pedido USSD foi modificado para um novo pedido USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"O pedido USSD foi modificado para um pedido Video DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"O pedido SS foi modificado para um pedido DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"O pedido SS foi modificado para um pedido Video DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"O pedido SS foi modificado para um pedido USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"O pedido SS foi modificado para um novo pedido SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Perfil de trabalho"</string>
@@ -1703,8 +1712,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 +1770,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..cce4bf0 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>
@@ -212,6 +212,7 @@
<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 bugs"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Finalizar sessão"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Obter relatório de bugs"</string>
<string name="bugreport_message" msgid="398447048750350456">"Isto coletará informações sobre o estado atual do dispositivo para enviá-las em uma mensagem de e-mail. Após iniciar o relatório de bugs, será necessário aguardar algum tempo até que esteja pronto para ser enviado."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Relatório interativo"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Quando o atalho está ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade.\n\n Recurso de acessibilidade atual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n É possível alterar o recurso em Configurações > Acessibilidade."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Desativar atalho"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Usar atalho"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inversão de cores"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Correção de cor"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atalho de acessibilidade ativou 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 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolha um recurso a ser usado ao tocar no botão Acessibilidade:"</string>
@@ -1634,7 +1640,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>
@@ -1681,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Durante a 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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Dormindo"</string>
<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">"Há um problema interno com seu dispositivo. Ele pode ficar instável até que você faça a redefinição para configuração original."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Há um problema interno com seu dispositivo. Entre em contato com o fabricante para saber mais detalhes."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"A solicitação USSD foi modificada para a solicitação DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"A solicitação USSD foi modificada para a solicitação SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"A solicitação USSD foi modificada para a nova solicitação USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"A solicitação USSD foi modificada para a solicitação DIAL de vídeo."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"A solicitação SS foi modificada para a solicitação DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"A solicitação SS foi modificada para a solicitação DIAL de vídeo."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"A solicitação SS foi modificada para a solicitação USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"A solicitação SS foi modificada para a nova solicitação SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Perfil de trabalho"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index d65eaa7..eece63e 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>
@@ -214,6 +214,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Opriți alimentarea"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Urgență"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Raport despre erori"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Încheiați sesiunea"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Executați un raport despre erori"</string>
<string name="bugreport_message" msgid="398447048750350456">"Acest raport va colecta informații despre starea actuală a dispozitivului, pentru a le trimite într-un e-mail. Aveți răbdare după pornirea raportului despre erori până când va fi gata de trimis."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Raport interactiv"</string>
@@ -1071,6 +1072,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 +1142,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 +1156,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>
@@ -1519,6 +1523,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Când comanda rapidă este activată, dacă apăsați ambele butoane de volum timp de 3 secunde, veți lansa o funcție de accesibilitate.\n\n Funcția actuală de accesibilitate:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puteți schimba funcția în Setări > Accesibilitate."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Dezactivați comanda rapidă"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Utilizați comanda rapidă"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inversarea culorilor"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Corecția culorii"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Comanda rapidă de accesibilitate a activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Comanda rapidă de accesibilitate a dezactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Alegeți o funcție pe care să o folosiți când atingeți butonul Accesibilitate:"</string>
@@ -1659,7 +1665,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>
@@ -1714,13 +1720,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Nopțile din zilele lucrătoare"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Weekend"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Eveniment"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Somn"</string>
<string name="muted_by" msgid="6147073845094180001">"Dezactivate de <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"A apărut o problemă internă pe dispozitiv, iar acesta poate fi instabil până la revenirea la setările din fabrică."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"A apărut o problemă internă pe dispozitiv. Pentru detalii, contactați producătorul."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Solicitarea USSD este modificată într-o solicitare DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Solicitarea USSD este modificată într-o solicitare SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Solicitarea USSD este modificată într-o nouă solicitare USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Solicitarea USSD este modificată într-o solicitare DIAL video."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Solicitarea SS este modificată într-o solicitare DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Solicitarea SS este modificată într-o solicitare DIAL video."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Solicitarea SS este modificată într-o solicitare USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Solicitarea SS este modificată într-o nouă solicitare SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profil de serviciu"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index fc9298c..53930c1 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>
@@ -216,6 +216,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"Закончить сеанс"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Отчет об ошибке"</string>
<string name="bugreport_message" msgid="398447048750350456">"Информация о текущем состоянии вашего устройства будет собрана и отправлена по электронной почте. Подготовка отчета займет некоторое время."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Интерактивный отчет"</string>
@@ -1091,6 +1092,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 +1164,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 +1178,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 +1547,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Инверсия цветов"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Коррекция цвета"</string>
<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 +1682,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 +1690,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,17 +1749,20 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Время сна"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD-запрос преобразован в DIAL-запрос"</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD-запрос преобразован в SS-запрос."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD-запрос преобразован в новый USSD-запрос."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD-запрос преобразован в запрос Video DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-запрос преобразован в DIAL-запрос."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS-запрос преобразован в запрос Video DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-запрос преобразован в USSD-запрос."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-запрос преобразован в новый SS-запрос."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Рабочий профиль"</string>
@@ -1852,14 +1860,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..2a1d635 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"සැසිය අවසන් කරන්න"</string>
<string name="bugreport_title" msgid="2667494803742548533">"දෝෂ වාර්තාවක් ගන්න"</string>
<string name="bugreport_message" msgid="398447048750350456">"ඊ-තැපැල් පණිවිඩයක් ලෙස යැවීමට මෙය ඔබගේ වත්මන් උපාංග තත්වය ගැන තොරතුරු එකතු කරනු ඇත. දෝෂ වාර්තාව ආරම්භ කර එය යැවීමට සූදානම් කරන තෙක් එයට කිසියම් කාලයක් ගතවනු ඇත; කරුණාකර ඉවසන්න."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"අන්තර්ක්රියා වාර්."</string>
@@ -1053,6 +1054,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 +1122,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 +1136,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>
@@ -1497,6 +1501,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"වර්ණ අපවර්තනය"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"වර්ණ නිවැරදි කිරීම"</string>
<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>
@@ -1628,7 +1634,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 +1642,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>
@@ -1684,13 +1689,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Weeknight"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"සති අන්තය"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"සිදුවීම"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"නිදා ගනිමින්"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD ඉල්ලීම DIAL ඉල්ලීම වෙත විකරණය කරන ලදී."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD ඉල්ලීම SS ඉල්ලීම වෙත විකරණය කරන ලදී."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD ඉල්ලීම නව USSD ඉල්ලීම වෙත විකරණය කරන ලදී."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD ඉල්ලීම Video DIAL ඉල්ලීම ලෙස වෙනස් කර ඇත."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS ඉල්ලීම DIAL ඉල්ලීම වෙත විකරණය කරන ලදී."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS ඉල්ලීම Video DIAL ඉල්ලීම ලෙස වෙනස් කර ඇත."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS ඉල්ලීම USSD ඉල්ලීම වෙත විකරණය කරන ලදී."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS ඉල්ලීම නව DIAL ඉල්ලීම වෙත විකරණය කරන ලදී."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"කාර්යාල පැතිකඩ"</string>
@@ -1784,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-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 9dacc7b..a0de5eb 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>
@@ -216,6 +216,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Vypnúť"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Tiesňové volanie"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Hlásenie o chybách"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Ukončiť reláciu"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Vytvoriť hlásenie chyby"</string>
<string name="bugreport_message" msgid="398447048750350456">"Týmto zhromaždíte informácie o aktuálnom stave zariadenia. Informácie je potom možné odoslať e-mailom, chvíľu však potrvá, kým bude hlásenie chyby pripravené na odoslanie. Prosíme vás preto o trpezlivosť."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktívne nahlásenie"</string>
@@ -1091,6 +1092,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 +1164,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 +1178,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>
@@ -1543,6 +1547,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Keď je skratka zapnutá, stlačením obidvoch tlačidiel hlasitosti na tri sekundy spustíte funkciu dostupnosti.\n\n Aktuálna funkcia dostupnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkciu môžete zmeniť v časti Nastavenia > Dostupnosť."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Vypnúť skratku"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Použiť skratku"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inverzia farieb"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Úprava farieb"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Skratka dostupnosti zapla službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Skratka dostupnosti vypla službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Klepnutím na tlačidlo dostupnosti vyberte požadovanú funkciu:"</string>
@@ -1676,7 +1682,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 +1690,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>
@@ -1748,13 +1753,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Noc pracovného dňa"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Víkend"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Udalosť"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Spánok"</string>
<string name="muted_by" msgid="6147073845094180001">"Stlmené aplikáciou <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Vo vašom zariadení došlo k internému problému. Môže byť nestabilné, kým neobnovíte jeho výrobné nastavenia."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Vo vašom zariadení došlo k internému problému. Ak chcete získať podrobné informácie, obráťte sa na jeho výrobcu."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Žiadosť USSD bola upravená na žiadosť DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Žiadosť USSD bola upravená na žiadosť SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Žiadosť USSD bola upravená na novú žiadosť USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Žiadosť USSD bola upravená na žiadosť Video DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Žiadosť SS bola upravená na žiadosť DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Žiadosť SS bola upravená na žiadosť Video DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Žiadosť SS bola upravená na žiadosť USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Žiadosť SS bola upravená na novú žiadosť SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Pracovný profil"</string>
@@ -1852,14 +1860,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..fb96279 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>
@@ -216,6 +216,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Izklopi"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Klic v sili"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Poročilo o napakah"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Končaj sejo"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Ustvari poročilo o napakah"</string>
<string name="bugreport_message" msgid="398447048750350456">"S tem bodo zbrani podatki o trenutnem stanju naprave, ki bodo poslani v e-poštnem sporočilu. Izvedba poročila o napakah in priprava trajata nekaj časa, zato bodite potrpežljivi."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktivno poročilo"</string>
@@ -1091,6 +1092,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 +1164,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 +1178,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>
@@ -1543,6 +1547,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Ko je bližnjica vklopljena, pritisnite gumba za glasnost in ju pridržite tri sekunde, če želite zagnati funkcijo za ljudi s posebnimi potrebami.\n\n Trenutna funkcija za ljudi s posebnimi potrebami:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkcijo lahko spremenite v »Nastavitve > Funkcije za ljudi s posebnimi potrebami«."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Izklopi bližnjico"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Uporabi bližnjico"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inverzija barv"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Popravljanje barv"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Bližnjica funkcij za ljudi s posebnimi potrebami je vklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Bližnjica funkcij za ljudi s posebnimi potrebami je izklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izberite funkcijo, ki jo želite uporabljati, ko se dotaknete gumba »Dostopnost«:"</string>
@@ -1676,7 +1682,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 +1690,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>
@@ -1748,13 +1753,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Noč med tednom"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Konec tedna"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Dogodek"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Spanje"</string>
<string name="muted_by" msgid="6147073845094180001">"Izklop zvoka: <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Vaša naprava ima notranjo napako in bo morda nestabilna, dokler je ne ponastavite na tovarniške nastavitve."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Vaša naprava ima notranjo napako. Če želite več informacij, se obrnite na proizvajalca."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Zahteva USSD je spremenjena v zahtevo DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Zahteva USSD je spremenjena v zahtevo SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Zahteva USSD je spremenjena v novo zahtevo USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Zahteva USSD je spremenjena v zahtevo Video DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Zahteva SS je spremenjena v zahtevo DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Zahteva SS je spremenjena v zahtevo Video DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Zahteva SS je spremenjena v zahtevo USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Zahteva SS je spremenjena v novo zahtevo SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Delovni profil"</string>
@@ -1852,14 +1860,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..4aee9bc 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Fik"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Urgjenca"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Raporti i defekteve në kod"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Jepi fund sesionit"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Merr raportin e defekteve në kod"</string>
<string name="bugreport_message" msgid="398447048750350456">"Ky funksion mundëson mbledhjen e informacioneve mbi gjendjen aktuale të pajisjes për ta dërguar si mesazh mail-i. Do të duhet pak kohë nga nisja e raportit të defekteve në kod. Faleminderit për durimin."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Raport interaktiv"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1500,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Kur shkurtorja është e aktivizuar, shtypja e të dy butonave për 3 sekonda do të nisë një funksion qasshmërie.\n\n Funksioni aktual i qasshmërisë:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Mund ta ndryshosh funksionin te Cilësimet > Qasshmëria."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Çaktivizo shkurtoren"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Përdor shkurtoren"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Kthimi i ngjyrës"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Korrigjimi i ngjyrës"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Shkurtorja e qasshmërisë e aktivizoi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Shkurtorja e qasshmërisë e çaktivizoi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Zgjidh një funksion për ta përdorur kur troket butonin e \"Qasshmërisë\":"</string>
@@ -1626,7 +1633,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 +1641,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>
@@ -1682,13 +1688,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Netët e javës"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Fundjava"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Ngjarje"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Në gjumë"</string>
<string name="muted_by" msgid="6147073845094180001">"Lënë në heshtje nga <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Ka një problem të brendshëm me pajisjen tënde. Ajo mund të jetë e paqëndrueshme derisa të rivendosësh të dhënat në gjendje fabrike."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Ka një problem të brendshëm me pajisjen tënde. Kontakto prodhuesin tënd për detaje."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Kërkesa USSD është modifikuar në kërkesën DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Kërkesa USSD është modifikuar në kërkesën SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Kërkesa USSD është modifikuar në kërkesën e re USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Kërkesa USSD është modifikuar në kërkesën Video DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Kërkesa SS është e modifikuar në kërkesën DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Kërkesa SS është e modifikuar në kërkesën Video DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Kërkesa SS është modifikuar në kërkesën USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Kërkesa SS është e modifikuar në kërkesën e re SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profili i punës"</string>
@@ -1782,14 +1791,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..146f8b3 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>
@@ -214,6 +214,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"Заврши сесију"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Направи извештај о грешци"</string>
<string name="bugreport_message" msgid="398447048750350456">"Овим ће се прикупити информације о тренутном стању уређаја како би биле послате у поруци е-поште. Од започињања извештаја о грешци до тренутка за његово слање проћи ће неко време; будите стрпљиви."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Интерактив. извештај"</string>
@@ -1071,6 +1072,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 +1142,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 +1156,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>
@@ -1519,6 +1523,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Инверзија боја"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Корекција боја"</string>
<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>
@@ -1659,7 +1665,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>
@@ -1714,13 +1720,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Спавање"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD захтев је промењен у DIAL захтев."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD захтев је промењен у SS захтев."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD захтев је промењен у нови USSD захтев."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD захтев је промењен у Video DIAL захтев."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS захтев је промењен у DIAL захтев."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS захтев је промењен у Video DIAL захтев."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS захтев је промењен у USSD захтев."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS захтев је промењен у нови SS захтев."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Профил за Work"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index cd5ec95..2705326 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Stäng av"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Nödsituation"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Felrapport"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Avsluta session"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Skapa felrapport"</string>
<string name="bugreport_message" msgid="398447048750350456">"Nu hämtas information om aktuell status för enheten, som sedan skickas i ett e-postmeddelade. Det tar en liten stund innan felrapporten är färdig och kan skickas, så vi ber dig ha tålamod."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiv rapport"</string>
@@ -431,7 +432,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 +453,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 +461,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 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"När kortkommandot har aktiverats startar du en tillgänglighetsfunktion genom att trycka ned båda volymknapparna i tre sekunder.\n\n Aktuell tillgänglighetsfunktion:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kan ändra funktionen i Inställningar > Tillgänglighet."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Inaktivera kortkommandot"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Använd kortkommandot"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inverterade färger"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Färgkorrigering"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktiverades av Aktivera tillgänglighet snabbt"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> inaktiverades av Aktivera tillgänglighet snabbt"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Välj en funktion som ska användas när du trycker på tillgänglighetsknappen:"</string>
@@ -1626,7 +1632,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 +1640,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>
@@ -1682,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Vardagskväll"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"I helgen"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Händelse"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"När jag sover"</string>
<string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> har stängt av ljudet"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Ett internt problem har uppstått i enheten, och det kan hända att problemet kvarstår tills du återställer standardinställningarna."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Ett internt problem har uppstått i enheten. Kontakta tillverkaren om du vill veta mer."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD-begäran har ändrats till en DIAL-begäran."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD-begäran har ändrats till en SS-begäran."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD-begäran har ändrats till en ny USSD-begäran."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD-begäran har ändrats till en Video DIAL-begäran."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-begäran har ändrats till en DIAL-begäran."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS-begäran har ändrats till en Video DIAL-begäran."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-begäran har ändrats till en USSD-begäran."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-begäran har ändrats till en ny SS-begäran."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Jobbprofil"</string>
@@ -1782,14 +1790,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..a8ab410 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>
@@ -210,6 +210,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Zima"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Dharura"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Ripoti ya hitilafu"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Maliza kipindi"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Chukua ripoti ya hitilafu"</string>
<string name="bugreport_message" msgid="398447048750350456">"Hii itakusanya maelezo kuhusu hali ya kifaa chako kwa sasa, na itume kama barua pepe. Itachukua muda mfupi tangu ripoti ya hitilafu ianze kuzalishwa hadi iwe tayari kutumwa; vumilia."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Ripoti ya kushirikiana"</string>
@@ -1049,6 +1050,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 +1118,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 +1132,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>
@@ -1493,6 +1497,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Unapowasha kipengele cha njia ya mkato, hatua ya kubonyeza vitufe vyote viwili vya sauti kwa dakika 3 itafungua kipengele cha zana za walio na matatizo ya kuona au kusikia.\n\n Kipengele kilichopo cha zana za walio na matatizo ya kuona au kusikia:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Unaweza kubadilisha kipengele hiki katika Mipangilio > Zana za walio na matatizo ya kuona au kusikia."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Zima kipengele cha Njia ya Mkato"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Tumia Njia ya Mkato"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Ugeuzaji wa Rangi"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Usahihishaji wa rangi"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Njia ya mkato ya zana za walio na matatizo ya kuona au kusikia imewasha <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Njia ya mkato ya zana za walio na matatizo ya kuona au kusikia imezima <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Chagua kipengele utakachotumia, ukigonga Kitufe cha zana za walio na matatizo ya kuona au kusikia."</string>
@@ -1632,7 +1638,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>
@@ -1679,13 +1685,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Usiku wa wiki"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Wikendi"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Tukio"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Kulala"</string>
<string name="muted_by" msgid="6147073845094180001">"Sauti imezimwa na <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Kuna hitilafu ya ndani ya kifaa chako, na huenda kisiwe thabiti mpaka urejeshe mipangilio ya kiwandani."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Kuna hitilafu ya ndani ya kifaa chako. Wasiliana na mtengenezaji wa kifaa chako kwa maelezo."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Ombi la USSD limerekebishwa na kuwa ombi la DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Ombi la USSD limerekebishwa na kuwa ombi la SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Ombi la USSD limerekebishwa na kuwa ombi jipya la USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Ombi la USSD limebadilishwa kuwa ombi la DIAL la Video."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Ombi la SS limerekebishwa na kuwa ombi la DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Ombi la SS limebadilishwa kuwa ombi la DIAL la Video."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Ombi la SS limerekebishwa na kuwa ombi la USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Ombi la SS limerekebishwa na kuwa ombi jipya la SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Wasifu wa kazini"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index e318851..c1526f3 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>
@@ -213,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"அமர்வை முடிக்கிறது"</string>
<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 +1052,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 +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>
@@ -1505,6 +1500,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"வண்ணத்தை நேர் எதிராக மாற்றுதல்"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"வண்ணத் திருத்தம்"</string>
<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 +1641,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,13 +1688,18 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"உறக்கத்தில்"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD கோரிக்கையானது DIAL கோரிக்கைக்கு மாற்றப்பட்டது."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD கோரிக்கையானது SS கோரிக்கைக்கு மாற்றப்பட்டது."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD கோரிக்கையானது புதிய USSD கோரிக்கைக்கு மாற்றப்பட்டது."</string>
+ <!-- no translation found for stk_cc_ussd_to_dial_video (585340552561515305) -->
+ <skip />
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS கோரிக்கையானது DIAL கோரிக்கைக்கு மாற்றப்பட்டது."</string>
+ <!-- no translation found for stk_cc_ss_to_dial_video (4306210904450719045) -->
+ <skip />
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS கோரிக்கையானது USSD கோரிக்கைக்கு மாற்றப்பட்டது."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS கோரிக்கையானது புதிய SS கோரிக்கைக்கு மாற்றப்பட்டது."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"பணி சுயவிவரம்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 8ae8401f..a96bcaf 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"సెషన్ను ముగించు"</string>
<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 +1052,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 +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>
@@ -1495,6 +1500,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"వర్ణ విలోమం"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"రంగు సవరణ"</string>
<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>
@@ -1634,7 +1641,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>
@@ -1681,13 +1688,18 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"నిద్రావస్థ"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD అభ్యర్థన డయల్ అభ్యర్థనగా సవరించబడింది."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD అభ్యర్థన SS అభ్యర్థనగా సవరించబడింది."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD అభ్యర్థన కొత్త USSD అభ్యర్థనగా సవరించబడింది."</string>
+ <!-- no translation found for stk_cc_ussd_to_dial_video (585340552561515305) -->
+ <skip />
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS అభ్యర్థన డయల్ అభ్యర్థనగా సవరించబడింది."</string>
+ <!-- no translation found for stk_cc_ss_to_dial_video (4306210904450719045) -->
+ <skip />
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS అభ్యర్థన USSD అభ్యర్థనగా సవరించబడింది."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS అభ్యర్థన కొత్త SS అభ్యర్థనగా సవరించబడింది."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"కార్యాలయ ప్రొఫైల్"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 1ccb751..2515241 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"จบเซสชัน"</string>
<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 +1052,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 +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="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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"เมื่อทางลัดเปิดอยู่ การกดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มเป็นเวลา 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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"การกลับสี"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"การปรับแก้สี"</string>
<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 +1632,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 +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>
@@ -1682,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"นอนหลับ"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"คำขอ USSD ได้รับการแก้ไขให้เป็นคำขอ DIAL"</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"คำขอ USSD ได้รับการแก้ไขให้เป็นคำขอ SS"</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"คำขอ USSD ได้รับการแก้ไขให้เป็นคำขอ USSD ใหม่"</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"คำขอ USSD ได้รับการแก้ไขให้เป็นคำขอ Video DIAL"</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"คำขอ SS ได้รับการแก้ไขให้เป็นคำขอ DIAL"</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"คำขอ SS ได้รับการแก้ไขให้เป็นคำขอ Video DIAL"</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"คำขอ SS ได้รับการแก้ไขให้เป็นคำขอ USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"คำขอ SS ได้รับการแก้ไขให้เป็นคำขอ SS ใหม่"</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"โปรไฟล์งาน"</string>
@@ -1782,14 +1790,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..d30267b 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"I-off"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Ulat sa bug"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Tapusin ang session"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Kunin ang ulat sa bug"</string>
<string name="bugreport_message" msgid="398447048750350456">"Mangongolekta ito ng impormasyon tungkol sa kasalukuyang katayuan ng iyong device, na ipapadala bilang mensaheng e-mail. Gugugol ito ng kaunting oras mula sa pagsisimula ng ulat sa bug hanggang sa handa na itong maipadala; mangyaring magpasensya."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interactive na ulat"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Kapag naka-on ang shortcut, magsisimula ang isang feature ng pagiging naa-access kapag pinindot ang parehong button ng volume sa loob ng 3 segundo.\n\n Kasalukuyang feature ng pagiging naa-access:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Maaari mong baguhin ang feature sa Mga Setting > Pagiging Naa-access."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"I-off ang Shortcut"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Gamitin ang Shortcut"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Pag-invert ng Kulay"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Pagwawasto ng Kulay"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Na-on ng Shortcut sa Accessibility ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Na-off ng Shortcut sa Accessibility ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pumili ng feature na gagamitin kapag na-tap mo ang button ng Pagiging Naa-access:"</string>
@@ -1626,7 +1632,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 +1640,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>
@@ -1682,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Weeknight"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Weekend"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Kaganapan"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Pag-sleep"</string>
<string name="muted_by" msgid="6147073845094180001">"Na-mute ng <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"May internal na problema sa iyong device, at maaaring hindi ito maging stable hanggang sa i-reset mo ang factory data."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"May internal na problema sa iyong device. Makipag-ugnayan sa iyong manufacturer upang malaman ang mga detalye."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Ginawang DIAL request ang USSD request."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Ginawang SS request ang USSD request."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Ginawang bagong USSD request ang USSD request."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Ginawang kahilingan sa Video DIAL ang kahilingan sa USSD."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Ginawang DIAL request ang SS request."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Ginawang kahilingan sa Video DIAL ang kahilingan sa SS."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Ginawang USSD request ang SS request."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Ginawang bagong SS request ang SS request."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profile sa trabaho"</string>
@@ -1782,14 +1790,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..e6646c4 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Kapat"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Acil durum"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Hata raporu"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Oturumu sonlandır"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Hata raporu al"</string>
<string name="bugreport_message" msgid="398447048750350456">"Bu rapor, e-posta iletisi olarak göndermek üzere cihazınızın şu anki durumuyla ilgili bilgi toplar. Hata raporu başlatıldıktan sonra hazır olması biraz zaman alabilir, lütfen sabırlı olun."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Etkileşimli rapor"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Kısayol açık olduğunda, ses düğmelerinin ikisini birden 3 saniyeliğine basılı tutmanız bir erişilebilirlik özelliğini başlatır.\n\n Geçerli erişilebilirlik özelliği:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Özelliği, Ayarlar > Erişilebilirlik seçeneğinden değiştirebilirsiniz."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Kısayolu Kapat"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Kısayolu Kullan"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Rengi Ters Çevirme"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Renk Düzeltme"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Erişilebilirlik Kısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini açtı"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Erişilebilirlik Kısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini kapattı"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Erişilebilirlik düğmesine dokunduğunuzda kullanmak üzere bir özellik seçin:"</string>
@@ -1634,7 +1640,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>
@@ -1681,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Hafta içi gece"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Hafta sonu"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Etkinlik"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Uyku"</string>
<string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> tarafından kapatıldı"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Cihazınızla ilgili dahili bir sorun oluştu ve fabrika verilerine sıfırlama işlemi gerçekleştirilene kadar kararsız çalışabilir."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Cihazınızla ilgili dahili bir sorun oluştu. Ayrıntılı bilgi için üreticinizle iletişim kurun."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD isteği DIAL isteği olarak değiştirildi."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD isteği SS isteği olarak değiştirildi."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD isteği yeni USSD isteği olarak değiştirildi."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD isteği Video DIAL isteği olarak değiştirildi."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS isteği DIAL isteği olarak değiştirildi."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS isteği, Video DIAL isteği olarak değiştirildi."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS isteği USSD isteği olarak değiştirildi."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS isteği yeni SS isteği olarak değiştirildi."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"İş profili"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 7d14e59..bfbe902 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,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"Завершити сеанс"</string>
<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 +262,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 +1092,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 +1164,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 +1178,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 +1547,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Інверсія кольорів"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Корекція кольорів"</string>
<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 +1682,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 +1690,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,13 +1753,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Під час сну"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Запит USSD перетворено на запит DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Запит USSD перетворено на запит SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Запит USSD перетворено на новий запит USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Запит USSD перетворено на запит Video DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Запит SS перетворено на запит DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Запит SS перетворено на запит Video DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Запит SS перетворено на запит USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Запит SS перетворено на новий запит SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Робочий профіль"</string>
@@ -1852,14 +1860,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..2155b34 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"سیشن ختم کریں"</string>
<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 +1052,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 +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>
@@ -1495,6 +1500,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"رنگ میں تبدیلی"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"رنگ کی تصحیح"</string>
<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>
@@ -1634,7 +1641,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>
@@ -1681,13 +1688,18 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"سونا"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD درخواست میں ترمیم کر کے DIAL درخواست بنا دی گئی ہے۔"</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD درخواست میں ترمیم کر کے SS درخواست بنا دی گئی ہے۔"</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD درخواست میں ترمیم کر کے نئی USSD درخواست بنا دی گئی ہے۔"</string>
+ <!-- no translation found for stk_cc_ussd_to_dial_video (585340552561515305) -->
+ <skip />
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS درخواست میں ترمیم کر کے DIAL درخواست بنا دی گئی ہے۔"</string>
+ <!-- no translation found for stk_cc_ss_to_dial_video (4306210904450719045) -->
+ <skip />
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS درخواست میں ترمیم کر کے USSD درخواست بنا دی گئی ہے۔"</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS درخواست میں ترمیم کر کے نئی SS درخواست بنا دی گئی ہے۔"</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"دفتری پروفائل"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index af5e0bd..c488473 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"O‘chirish"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Favqulodda chaqiruv"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Nosozlik haqida ma’lumot berish"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Seansni yakunlash"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Xatoliklar hisoboti"</string>
<string name="bugreport_message" msgid="398447048750350456">"Qurilmangiz holati haqidagi ma’lumotlar to‘planib, e-pochta orqali yuboriladi. Hisobotni tayyorlash biroz vaqt olishi mumkin."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiv hisobot"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1412,7 +1417,7 @@
<string name="fingerprints" msgid="4516019619850763049">"Barmoq izlari:"</string>
<string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 barmoq izi:"</string>
<string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 barmoq izi:"</string>
- <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Barchasini ko‘rish"</string>
+ <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Hammasi"</string>
<string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"Harakat turini tanlang"</string>
<string name="share_action_provider_share_with" msgid="5247684435979149216">"Ulashish"</string>
<string name="sending" msgid="3245653681008218030">"Jo‘natilmoqda…"</string>
@@ -1495,6 +1500,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Maxsus imkoniyatlar funksiyasidan foydalanish uchun u yoniqligida ikkala ovoz balandligini boshqarish tugmasini 3 soniya bosib turing.\n\n Joriy maxsus imkoniyatlar funksiyasi:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Bu funksiyani Sozlamalar > Maxsus imkoniyatlar orqali o‘zgartirish mumkin."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Tezkor ishga tushirishni o‘chirib qo‘yish"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Tezkor ishga tushirishdan foydalanish"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Ranglarni akslantirish"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Rangni tuzatish"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmati yoqildi"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmati o‘chirib qo‘yildi"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Maxsus imkoniyatlar tugmasi bosilganda ishga tushadigan funksiyani tanlang:"</string>
@@ -1634,7 +1641,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>
@@ -1681,13 +1688,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Ish kunlari kechqurun"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Dam olish kunlari"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Tadbir"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Uyquda"</string>
<string name="muted_by" msgid="6147073845094180001">"“<xliff:g id="THIRD_PARTY">%1$s</xliff:g>” tomonidan ovozsiz qilingan"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Qurilmangiz bilan bog‘liq ichki muammo mavjud. U zavod sozlamalari tiklanmaguncha barqaror ishlamasligi mumkin."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Qurilmangiz bilan bog‘liq ichki muammo mavjud. Tafsilotlar uchun qurilmangiz ishlab chiqaruvchisiga murojaat qiling."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD so‘rovi DIAL so‘roviga o‘zgartirildi."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD so‘rovi SS so‘roviga o‘zgartirildi."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD so‘rovi yangi USSD so‘roviga o‘zgartirildi."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD so‘rovi Video DIAL so‘roviga o‘zgartirildi."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS so‘rovi DIAL so‘roviga o‘zgartirildi."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS so‘rovi Video DIAL so‘roviga o‘zgartirildi."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS so‘rovi USSD so‘roviga o‘zgartirildi."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS so‘rovi yangi SS so‘roviga o‘zgartirildi."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Ishchi profil"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index c3938aa..5f72834 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Tắt nguồn"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Khẩn cấp"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Báo cáo lỗi"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Kết thúc phiên"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Nhận báo cáo lỗi"</string>
<string name="bugreport_message" msgid="398447048750350456">"Báo cáo này sẽ thu thập thông tin về tình trạng thiết bị hiện tại của bạn, để gửi dưới dạng thông báo qua email. Sẽ mất một chút thời gian kể từ khi bắt đầu báo cáo lỗi cho tới khi báo cáo sẵn sàng để gửi; xin vui lòng kiên nhẫn."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Báo cáo tương tác"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Khi phím tắt được bật, nhấn cả hai nút âm lượng trong 3 giây sẽ bắt đầu một tính năng trợ năng.\n\n Tính năng trợ năng hiện tại:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Bạn có thể thay đổi tính năng trong Cài đặt > Trợ năng."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Tắt phím tắt"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Sử dụng phím tắt"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Đảo màu"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Sửa màu"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Đã bật phím tắt trợ năng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Đã tắt phím tắt trợ năng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Chọn tính năng sẽ sử dụng khi bạn nhấn nút Trợ năng:"</string>
@@ -1626,7 +1632,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 +1640,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>
@@ -1682,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Đêm trong tuần"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Cuối tuần"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Sự kiện"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Khi đang ngủ"</string>
<string name="muted_by" msgid="6147073845094180001">"Do <xliff:g id="THIRD_PARTY">%1$s</xliff:g> tắt tiếng"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Đã xảy ra sự cố nội bộ với thiết bị của bạn và thiết bị có thể sẽ không ổn định cho tới khi bạn thiết lập lại dữ liệu ban đầu."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Đã xảy ra sự cố nội bộ với thiết bị. Hãy liên hệ với nhà sản xuất của bạn để biết chi tiết."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Yêu cầu USSD được sửa đổi thành yêu cầu DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Yêu cầu USSD được sửa đổi thành yêu cầu SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Yêu cầu USSD được sửa đổi thành yêu cầu USSD mới."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Yêu cầu USSD được sửa đổi thành yêu cầu DIAL video."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Yêu cầu SS được sửa đổi thành yêu cầu DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Yêu cầu SS được sửa đổi thành yêu cầu DIAL video."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Yêu cầu SS được sửa đổi thành yêu cầu USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Yêu cầu SS được sửa đổi thành yêu cầu SS mới."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Hồ sơ công việc"</string>
@@ -1782,14 +1790,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..028c082 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"结束会话"</string>
<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 +1052,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 +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">"此 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 +1134,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>
@@ -1495,6 +1499,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"颜色反转"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"色彩校正"</string>
<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>
@@ -1634,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>
@@ -1681,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"睡眠"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD 请求已修改为 DIAL 请求。"</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD 请求已修改为 SS 请求。"</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD 请求已修改为新的 USSD 请求。"</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD 请求已修改为视频 DIAL 请求。"</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS 请求已修改为 DIAL 请求。"</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS 请求已修改为视频 DIAL 请求。"</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS 请求已修改为 USSD 请求。"</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS 请求已修改为新的 SS 请求。"</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"工作资料"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index b9c83b3..2da0d4a 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"結束工作階段"</string>
<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 +1052,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 +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,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 +1499,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"色彩反轉"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"色彩校正"</string>
<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 +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>
@@ -1635,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>
@@ -1682,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"睡眠"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD 要求已修改為 DIAL 要求。"</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD 要求已修改為 SS 要求。"</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD 要求已修改為新的 USSD 要求。"</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD 要求已修改為影片 DIAL 要求。"</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS 要求已修改為 DIAL 要求。"</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS 要求已修改為影片 DIAL 要求。"</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS 要求已修改為 USSD 要求。"</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS 要求已修改為新的 SS 要求。"</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"工作設定檔"</string>
@@ -1782,14 +1790,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..4f2492f 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>
@@ -212,6 +212,7 @@
<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>
+ <string name="global_action_logout" msgid="935179188218826050">"結束"</string>
<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 +1052,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 +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,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 +1499,8 @@
<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>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"色彩反轉"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"色彩校正"</string>
<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 +1632,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 +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>
@@ -1682,13 +1687,16 @@
<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>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"睡眠"</string>
<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>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD 要求已改為 DIAL 要求。"</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD 要求已改為 SS 要求。"</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD 要求已改為新的 USSD 要求。"</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD 要求已改為影片 DIAL 要求。"</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS 要求已改為 DIAL 要求。"</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS 要求已改為影片 DIAL 要求。"</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS 要求已改為 USSD 要求。"</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS 要求已改為新的 SS 要求。"</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Work 設定檔"</string>
@@ -1782,14 +1790,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..2977a85 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>
@@ -212,6 +212,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Vala amandla"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"Isimo esiphuthumayo"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Umbiko wephutha"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"Phothula isikhathi"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Thatha umbiko wesiphazamiso"</string>
<string name="bugreport_message" msgid="398447048750350456">"Lokhu kuzoqoqa ulwazi mayelana nesimo samanje sedivayisi yakho, ukuthumela imilayezo ye-imeyili. Kuzothatha isikhathi esincane kusuka ekuqaleni umbiko wesiphazamiso uze ulungele ukuthunyelwa; sicela ubekezele."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Umbiko obandakanyayo"</string>
@@ -1051,6 +1052,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 +1120,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 +1134,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>
@@ -1495,6 +1499,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Uma kuvulwe isinqamuleli, ukucindezela zombili izinkinobho zevolumu amasekhondi angu-3 kuzoqala isici sokufinyelela.\n\n Isici samanje sokufinyelela:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Ungashintsha isici kuzilungiselelo > Ukufinyelela."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Vala isinqamuleli"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Sebenzisa isinqamuleli"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"Ukuguqulwa kombala"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"Ukulungiswa kombala"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Isinqamuleli sokufinyelela sivule i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Isinqamuleli sokufinyelela sivale i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Khetha isici ozosisebenzisa uma uthepha inkinobho yokufinyelela:"</string>
@@ -1626,7 +1632,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 +1640,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>
@@ -1682,13 +1687,16 @@
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Ubusuku beviki"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Ngempelasonto"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"Umcimbi"</string>
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Ulele"</string>
<string name="muted_by" msgid="6147073845094180001">"Ithuliswe ngu-<xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
<string name="system_error_wipe_data" msgid="6608165524785354962">"Kukhona inkinga yangaphakathi ngedivayisi yakho, futhi ingase ibe engazinzile kuze kube yilapho usetha kabusha yonke idatha."</string>
<string name="system_error_manufacturer" msgid="8086872414744210668">"Kukhona inkinga yangaphakathi ngedivayisi yakho. Xhumana nomkhiqizi wakho ukuze uthole imininingwane."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Isicelo se-USSD siguqulelwe kusicelo se-DIAL."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Isicelo se-USSD siguqulelwe kusicelo se-SS."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Isicelo se-USSD siguqulelwe kusicelo esisha se-USSD."</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"Isicelo se-USSD siguqulelwe kusicelo se-DIAL."</string>
<string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Isicelo se-SS siguqulelwe kusicelo se-DIAL."</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"Isicelo se-SS siguqulelwe kusicelo se-DIAL."</string>
<string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Isicelo se-SS siguqulelwe kusicelo se-USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Isicelo se-SS siguqulelwe kusicelo esisha se-SS."</string>
<string name="notification_work_profile_content_description" msgid="4600554564103770764">"Iphrofayela yomsebenzi"</string>
@@ -1782,14 +1790,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 9a0eafd..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" />
@@ -3291,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>
@@ -7565,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>
<!-- =============================== -->
@@ -8535,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..efbe9c2 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
@@ -1365,6 +1375,13 @@
{@link android.os.Build.VERSION#CODENAME Build.VERSION.CODENAME}. -->
<attr name="compileSdkVersionCodename" format="string" />
+ <!-- The (optional) fully-qualified name for a subclass of
+ {@link android.app.AppComponentFactory} that the system uses to instantiate
+ every other manifest defined class. Most applications
+ don't need this attribute. If it's not specified, the system
+ instantiates items without it.-->
+ <attr name="appComponentFactory" format="string" />
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -1386,6 +1403,7 @@
{@link #AndroidManifestUsesFeature uses-feature}. -->
<declare-styleable name="AndroidManifest">
<attr name="versionCode" />
+ <attr name="versionCodeMajor" />
<attr name="versionName" />
<attr name="revisionCode" />
<attr name="sharedUserId" />
@@ -1535,6 +1553,8 @@
<!-- Declares the kind of classloader this application's classes must be loaded with -->
<attr name="classLoader" />
+ <attr name="appComponentFactory" />
+
</declare-styleable>
<!-- The <code>permission</code> tag declares a security permission that can be
used to control access from other packages to specific components or
@@ -1784,6 +1804,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 65a7ec6..8377751 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>
@@ -957,12 +963,6 @@
-->
<integer name="config_longPressOnBackBehavior">0</integer>
- <!-- Control the behavior when the user panic presses the back button.
- 0 - Nothing
- 1 - Go to home
- -->
- <integer name="config_backPanicBehavior">0</integer>
-
<!-- Control the behavior when the user short presses the power button.
0 - Nothing
1 - Go to sleep (doze)
@@ -1295,6 +1295,22 @@
<integer-array name="config_autoBrightnessLcdBacklightValues">
</integer-array>
+ <!-- Array of desired screen brightness in nits corresponding to the lux values
+ in the config_autoBrightnessLevels array. As with config_screenBrightnessMinimumNits and
+ config_screenBrightnessMaximumNits, the display brightness is defined as the measured
+ brightness of an all-white image.
+
+ If this is defined then:
+ - config_autoBrightnessLcdBacklightValues should not be defined
+ - config_screenBrightnessMinimumNits must be defined
+ - config_screenBrightnessMaximumNits must be defined
+
+ This array should have size one greater than the size of the config_autoBrightnessLevels
+ array. The brightness values must be non-negative and non-decreasing. This must be
+ overridden in platform specific overlays -->
+ <array name="config_autoBrightnessDisplayValuesNits">
+ </array>
+
<!-- Array of output values for button backlight corresponding to the LUX values
in the config_autoBrightnessLevels array. This array should have size one greater
than the size of the config_autoBrightnessLevels array.
@@ -1331,6 +1347,29 @@
<item>200</item>
</integer-array>
+ <!-- The minimum brightness of the display in nits. On OLED displays this should be measured
+ with an all white image while the display is fully on and the backlight is set to
+ config_screenBrightnessSettingMinimum or config_screenBrightnessSettingDark, whichever
+ is darker.
+
+ If this and config_screenBrightnessMinimumNits are set, then the display's brightness
+ range is assumed to be linear between
+ (config_screenBrightnessSettingMinimum, config_screenBrightnessMinimumNits) and
+ (config_screenBrightnessSettingMaximum, config_screenBrightnessMaximumNits). -->
+ <item name="config_screenBrightnessMinimumNits" format="float" type="dimen">-1.0</item>
+
+ <!-- The maximum brightness of the display in nits. On OLED displays this should be measured
+ with an all white image while the display is fully on and the "backlight" is set to
+ config_screenBrightnessSettingMaximum. Note that this value should *not* reflect the
+ maximum brightness value for any high brightness modes but only the maximum brightness
+ value obtainable in a sustainable manner.
+
+ If this and config_screenBrightnessMinimumNits are set to something non-negative, then the
+ display's brightness range is assumed to be linear between
+ (config_screenBrightnessSettingMinimum, config_screenBrightnessMaximumNits) and
+ (config_screenBrightnessSettingMaximum, config_screenBrightnessMaximumNits). -->
+ <item name="config_screenBrightnessMaximumNits" format="float" type="dimen">-1.0</item>
+
<!-- Array of ambient lux threshold values. This is used for determining hysteresis constraint
values by calculating the index to use for lookup and then setting the constraint value
to the corresponding value of the array. The new brightening hysteresis constraint value
@@ -1381,6 +1420,9 @@
<!-- True if WallpaperService is enabled -->
<bool name="config_enableWallpaperService">true</bool>
+ <!-- Class name of WallpaperManagerService. -->
+ <string name="config_wallpaperManagerServiceName">com.android.server.wallpaper.WallpaperManagerService</string>
+
<!-- Enables the TimeZoneRuleManager service. This is the master switch for the updateable time
zone update mechanism. -->
<bool name="config_enableUpdateableTimeZoneRules">false</bool>
@@ -2435,10 +2477,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 +3213,17 @@
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 -->
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/core/res/res/values/disallowed_apps_managed_device.xml
similarity index 67%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/res/res/values/disallowed_apps_managed_device.xml
index 353728a..8940b15 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/res/res/values/disallowed_apps_managed_device.xml
@@ -1,11 +1,13 @@
-/*
+<?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
+ * 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,
@@ -13,13 +15,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package com.android.server.timezone;
-
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
-
- long currentTimestamp();
-}
+-->
+<resources>
+ <!-- A list of apps to be removed from the managed device. -->
+ <string-array name="disallowed_apps_managed_device">
+ </string-array>
+</resources>
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/core/res/res/values/disallowed_apps_managed_profile.xml
similarity index 67%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/res/res/values/disallowed_apps_managed_profile.xml
index 353728a..e3a513f 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/res/res/values/disallowed_apps_managed_profile.xml
@@ -1,11 +1,13 @@
-/*
+<?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
+ * 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,
@@ -13,13 +15,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package com.android.server.timezone;
-
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
-
- long currentTimestamp();
-}
+-->
+<resources>
+ <!-- A list of apps to be removed from the managed profile. -->
+ <string-array name="disallowed_apps_managed_profile">
+ </string-array>
+</resources>
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/core/res/res/values/disallowed_apps_managed_user.xml
similarity index 67%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/res/res/values/disallowed_apps_managed_user.xml
index 353728a..b7b645d 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/res/res/values/disallowed_apps_managed_user.xml
@@ -1,11 +1,13 @@
-/*
+<?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
+ * 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,
@@ -13,13 +15,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package com.android.server.timezone;
-
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
-
- long currentTimestamp();
-}
+-->
+<resources>
+ <!-- A list of apps to be removed from the managed user. -->
+ <string-array name="disallowed_apps_managed_user">
+ </string-array>
+</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e370786..8540ff1 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2853,6 +2853,13 @@
<!-- @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 name="appComponentFactory" />
</public-group>
<public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/required_apps_managed_device.xml b/core/res/res/values/required_apps_managed_device.xml
new file mode 100644
index 0000000..0ac706f
--- /dev/null
+++ b/core/res/res/values/required_apps_managed_device.xml
@@ -0,0 +1,31 @@
+<?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.
+ */
+-->
+<resources>
+ <!-- A list of apps to be retained on the managed device.
+ Takes precedence over the disallowed apps lists. -->
+ <string-array name="required_apps_managed_device">
+ <item>com.android.settings</item>
+ <item>com.android.contacts</item>
+ <item>com.android.dialer</item>
+ <item>com.android.stk</item> <!-- Required by com.android.phone by certain carriers -->
+ <item>com.android.providers.downloads</item>
+ <item>com.android.providers.downloads.ui</item>
+ <item>com.android.documentsui</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values/required_apps_managed_profile.xml b/core/res/res/values/required_apps_managed_profile.xml
new file mode 100644
index 0000000..a0b8492
--- /dev/null
+++ b/core/res/res/values/required_apps_managed_profile.xml
@@ -0,0 +1,29 @@
+<?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.
+ */
+-->
+<resources>
+ <!-- A list of apps to be retained in the managed profile.
+ Takes precedence over the disallowed apps lists. -->
+ <string-array name="required_apps_managed_profile">
+ <item>com.android.contacts</item>
+ <item>com.android.settings</item>
+ <item>com.android.providers.downloads</item>
+ <item>com.android.providers.downloads.ui</item>
+ <item>com.android.documentsui</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values/required_apps_managed_user.xml b/core/res/res/values/required_apps_managed_user.xml
new file mode 100644
index 0000000..e8fdb21
--- /dev/null
+++ b/core/res/res/values/required_apps_managed_user.xml
@@ -0,0 +1,31 @@
+<?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.
+ */
+-->
+<resources>
+ <!-- A list of apps to be retained on the managed user.
+ Takes precedence over the disallowed apps lists. -->
+ <string-array name="required_apps_managed_user">
+ <item>com.android.settings</item>
+ <item>com.android.contacts</item>
+ <item>com.android.dialer</item>
+ <item>com.android.stk</item> <!-- Required by com.android.phone by certain carriers -->
+ <item>com.android.providers.downloads</item>
+ <item>com.android.providers.downloads.ui</item>
+ <item>com.android.documentsui</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2f1d679..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] -->
@@ -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/symbols.xml b/core/res/res/values/symbols.xml
index a115816..be7ce5f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -287,6 +287,7 @@
<java-symbol type="bool" name="split_action_bar_is_narrow" />
<java-symbol type="bool" name="config_useVolumeKeySounds" />
<java-symbol type="bool" name="config_enableWallpaperService" />
+ <java-symbol type="string" name="config_wallpaperManagerServiceName" />
<java-symbol type="bool" name="config_enableUpdateableTimeZoneRules" />
<java-symbol type="bool" name="config_timeZoneRulesUpdateTrackingEnabled" />
<java-symbol type="string" name="config_timeZoneRulesUpdaterPackage" />
@@ -391,6 +392,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" />
@@ -422,7 +425,6 @@
<java-symbol type="integer" name="config_veryLongPressOnPowerBehavior" />
<java-symbol type="integer" name="config_veryLongPressTimeout" />
<java-symbol type="integer" name="config_longPressOnBackBehavior" />
- <java-symbol type="integer" name="config_backPanicBehavior" />
<java-symbol type="integer" name="config_lowMemoryKillerMinFreeKbytesAdjust" />
<java-symbol type="integer" name="config_lowMemoryKillerMinFreeKbytesAbsolute" />
<java-symbol type="integer" name="config_max_pan_devices" />
@@ -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" />
@@ -1206,6 +1213,18 @@
<java-symbol type="array" name="config_telephonyHardware" />
<java-symbol type="array" name="config_keySystemUuidMapping" />
<java-symbol type="array" name="config_gpsParameters" />
+ <java-symbol type="array" name="required_apps_managed_user" />
+ <java-symbol type="array" name="required_apps_managed_profile" />
+ <java-symbol type="array" name="required_apps_managed_device" />
+ <java-symbol type="array" name="disallowed_apps_managed_user" />
+ <java-symbol type="array" name="disallowed_apps_managed_profile" />
+ <java-symbol type="array" name="disallowed_apps_managed_device" />
+ <java-symbol type="array" name="vendor_required_apps_managed_user" />
+ <java-symbol type="array" name="vendor_required_apps_managed_profile" />
+ <java-symbol type="array" name="vendor_required_apps_managed_device" />
+ <java-symbol type="array" name="vendor_disallowed_apps_managed_user" />
+ <java-symbol type="array" name="vendor_disallowed_apps_managed_profile" />
+ <java-symbol type="array" name="vendor_disallowed_apps_managed_device" />
<java-symbol type="drawable" name="default_wallpaper" />
<java-symbol type="drawable" name="default_lock_wallpaper" />
@@ -2259,6 +2278,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 +2928,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 +2951,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 +3180,13 @@
<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" />
+
+ <java-symbol type="dimen" name="config_screenBrightnessMinimumNits" />
+ <java-symbol type="dimen" name="config_screenBrightnessMaximumNits" />
+ <java-symbol type="array" name="config_autoBrightnessDisplayValuesNits" />
</resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 3fa0d3b..39310a8 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -69,6 +69,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.Button</item>
<item name="buttonStyleSmall">@style/Widget.DeviceDefault.Button.Small</item>
@@ -224,6 +225,7 @@
<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>
@@ -243,6 +245,7 @@
<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>
@@ -264,6 +267,7 @@
<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>
@@ -284,6 +288,7 @@
<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>
@@ -303,6 +308,7 @@
<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 -->
@@ -331,6 +337,7 @@
<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>
@@ -349,6 +356,7 @@
<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>
@@ -368,6 +376,7 @@
<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>
@@ -403,6 +412,7 @@
<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>
@@ -423,6 +433,7 @@
<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>
@@ -441,6 +452,7 @@
<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>
@@ -461,6 +473,7 @@
<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>
@@ -480,6 +493,7 @@
<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>
@@ -499,6 +513,7 @@
<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>
@@ -518,6 +533,7 @@
<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>
@@ -537,6 +553,7 @@
<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>
@@ -556,6 +573,7 @@
<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>
@@ -573,6 +591,7 @@
<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>
@@ -590,6 +609,7 @@
<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>
@@ -614,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>
@@ -762,6 +783,7 @@
<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>
@@ -780,6 +802,7 @@
<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>
@@ -799,6 +822,7 @@
<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>
@@ -820,6 +844,7 @@
<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>
@@ -840,6 +865,7 @@
<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>
@@ -855,6 +881,7 @@
<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>
@@ -885,6 +912,7 @@
<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>
@@ -903,6 +931,7 @@
<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>
@@ -922,6 +951,7 @@
<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>
@@ -967,6 +997,7 @@
<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>
@@ -987,6 +1018,7 @@
<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>
@@ -1005,6 +1037,7 @@
<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>
@@ -1025,6 +1058,7 @@
<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>
@@ -1044,6 +1078,7 @@
<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>
@@ -1061,6 +1096,7 @@
<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>
@@ -1078,6 +1114,7 @@
<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>
@@ -1088,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>
@@ -1107,6 +1145,7 @@
<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>
@@ -1125,6 +1164,7 @@
<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>
@@ -1153,6 +1193,7 @@
<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>
@@ -1171,6 +1212,7 @@
<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>
@@ -1189,6 +1231,7 @@
<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>
@@ -1207,6 +1250,7 @@
<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>
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/services/core/java/com/android/server/timezone/ClockHelper.java b/core/res/res/values/vendor_disallowed_apps_managed_device.xml
similarity index 65%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/res/res/values/vendor_disallowed_apps_managed_device.xml
index 353728a..c826d27 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/res/res/values/vendor_disallowed_apps_managed_device.xml
@@ -1,11 +1,13 @@
-/*
+<?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
+ * 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,
@@ -13,13 +15,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package com.android.server.timezone;
-
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
-
- long currentTimestamp();
-}
+-->
+<resources>
+ <!-- A list of apps to be removed from the managed device by a particular vendor. -->
+ <string-array name="vendor_disallowed_apps_managed_device">
+ </string-array>
+</resources>
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/core/res/res/values/vendor_disallowed_apps_managed_profile.xml
similarity index 65%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/res/res/values/vendor_disallowed_apps_managed_profile.xml
index 353728a..5fcb2778 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/res/res/values/vendor_disallowed_apps_managed_profile.xml
@@ -1,11 +1,13 @@
-/*
+<?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
+ * 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,
@@ -13,13 +15,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package com.android.server.timezone;
-
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
-
- long currentTimestamp();
-}
+-->
+<resources>
+ <!-- A list of apps to be removed from the managed profile by a particular vendor. -->
+ <string-array name="vendor_disallowed_apps_managed_profile">
+ </string-array>
+</resources>
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/core/res/res/values/vendor_disallowed_apps_managed_user.xml
similarity index 65%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/res/res/values/vendor_disallowed_apps_managed_user.xml
index 353728a..3355d77 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/res/res/values/vendor_disallowed_apps_managed_user.xml
@@ -1,11 +1,13 @@
-/*
+<?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
+ * 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,
@@ -13,13 +15,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package com.android.server.timezone;
-
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
-
- long currentTimestamp();
-}
+-->
+<resources>
+ <!-- A list of apps to be removed from the managed user by a particular vendor. -->
+ <string-array name="vendor_disallowed_apps_managed_user">
+ </string-array>
+</resources>
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/core/res/res/values/vendor_required_apps_managed_device.xml
similarity index 61%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/res/res/values/vendor_required_apps_managed_device.xml
index 353728a..e684e22 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/res/res/values/vendor_required_apps_managed_device.xml
@@ -1,11 +1,13 @@
-/*
+<?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
+ * 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,
@@ -13,13 +15,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package com.android.server.timezone;
-
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
-
- long currentTimestamp();
-}
+-->
+<resources>
+ <!-- A list of apps to be retained on the managed device by a particular vendor.
+ Takes precedence over the disallowed apps lists. -->
+ <string-array name="vendor_required_apps_managed_device">
+ </string-array>
+</resources>
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/core/res/res/values/vendor_required_apps_managed_profile.xml
similarity index 60%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/res/res/values/vendor_required_apps_managed_profile.xml
index 353728a..4a3edf8 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/res/res/values/vendor_required_apps_managed_profile.xml
@@ -1,11 +1,13 @@
-/*
+<?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
+ * 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,
@@ -13,13 +15,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package com.android.server.timezone;
-
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
-
- long currentTimestamp();
-}
+-->
+<resources>
+ <!-- A list of apps to be retained in the managed profile by a particular vendor.
+ Takes precedence over the disallowed apps lists. -->
+ <string-array name="vendor_required_apps_managed_profile">
+ </string-array>
+</resources>
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/core/res/res/values/vendor_required_apps_managed_user.xml
similarity index 61%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to core/res/res/values/vendor_required_apps_managed_user.xml
index 353728a..71dbd62 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/core/res/res/values/vendor_required_apps_managed_user.xml
@@ -1,11 +1,13 @@
-/*
+<?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
+ * 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,
@@ -13,13 +15,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package com.android.server.timezone;
-
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
-
- long currentTimestamp();
-}
+-->
+<resources>
+ <!-- A list of apps to be retained on the managed user by a particular vendor.
+ Takes precedence over the disallowed apps lists. -->
+ <string-array name="vendor_required_apps_managed_user">
+ </string-array>
+</resources>
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/ConnectivityManagerTest/Android.mk b/core/tests/ConnectivityManagerTest/Android.mk
index 39cf4a4..5ed93f3 100644
--- a/core/tests/ConnectivityManagerTest/Android.mk
+++ b/core/tests/ConnectivityManagerTest/Android.mk
@@ -18,8 +18,8 @@
# We only want this apk build for tests.
LOCAL_MODULE_TAGS := tests
-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 all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/core/tests/bandwidthtests/Android.mk b/core/tests/bandwidthtests/Android.mk
index 2af92df..ff9a0fe 100644
--- a/core/tests/bandwidthtests/Android.mk
+++ b/core/tests/bandwidthtests/Android.mk
@@ -22,8 +22,12 @@
LOCAL_SRC_FILES := \
$(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := android.test.runner org.apache.http.legacy
-LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
+LOCAL_JAVA_LIBRARIES := \
+ android.test.runner \
+ org.apache.http.legacy \
+ android.test.base \
+
+LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_PACKAGE_NAME := BandwidthTests
include $(BUILD_PACKAGE)
diff --git a/core/tests/bluetoothtests/Android.mk b/core/tests/bluetoothtests/Android.mk
index f53419a..744e5b0 100644
--- a/core/tests/bluetoothtests/Android.mk
+++ b/core/tests/bluetoothtests/Android.mk
@@ -8,8 +8,8 @@
LOCAL_SRC_FILES := \
$(call all-java-files-under, src)
-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
LOCAL_PACKAGE_NAME := BluetoothTests
LOCAL_CERTIFICATE := platform
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/assets/fonts/LineBreakingOverhangsTestFont.ttf b/core/tests/coretests/assets/fonts/LineBreakingOverhangsTestFont.ttf
deleted file mode 100644
index cf769ed..0000000
--- a/core/tests/coretests/assets/fonts/LineBreakingOverhangsTestFont.ttf
+++ /dev/null
Binary files differ
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/LineBreakingOverhangsTestFont.ttx b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx
similarity index 65%
rename from core/tests/coretests/assets/fonts/LineBreakingOverhangsTestFont.ttx
rename to core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx
index 04d85922..0cf0f79 100644
--- a/core/tests/coretests/assets/fonts/LineBreakingOverhangsTestFont.ttx
+++ b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx
@@ -13,35 +13,31 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.9">
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
<GlyphOrder>
- <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
<GlyphID id="0" name=".notdef"/>
- <GlyphID id="1" name="space"/>
- <GlyphID id="2" name="R"/>
- <GlyphID id="3" name="a"/>
- <GlyphID id="4" name="y"/>
+ <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>
- <!-- Most of this table will be recalculated by the compiler -->
<tableVersion value="1.0"/>
<fontRevision value="1.0"/>
- <checkSumAdjustment value="0x26d0d624"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
<magicNumber value="0x5f0f3cf5"/>
<flags value="00000000 00000011"/>
- <unitsPerEm value="1000"/>
- <created value="Tue Oct 3 23:00:00 2017"/>
- <modified value="Tue Oct 3 23:33:15 2017"/>
- <xMin value="-1500"/>
- <yMin value="0"/>
- <xMax value="5000"/>
- <yMax value="1000"/>
+ <unitsPerEm value="100"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
<macStyle value="00000000 00000000"/>
<lowestRecPPEM value="7"/>
<fontDirectionHint value="2"/>
- <indexToLocFormat value="0"/>
<glyphDataFormat value="0"/>
</head>
@@ -50,10 +46,6 @@
<ascent value="1000"/>
<descent value="-200"/>
<lineGap value="0"/>
- <advanceWidthMax value="1000"/>
- <minLeftSideBearing value="-1500"/>
- <minRightSideBearing value="-4000"/>
- <xMaxExtent value="5000"/>
<caretSlopeRise value="1"/>
<caretSlopeRun value="0"/>
<caretOffset value="0"/>
@@ -62,17 +54,10 @@
<reserved2 value="0"/>
<reserved3 value="0"/>
<metricDataFormat value="0"/>
- <numberOfHMetrics value="1"/>
</hhea>
<maxp>
- <!-- Most of this table will be recalculated by the compiler -->
<tableVersion value="0x10000"/>
- <numGlyphs value="5"/>
- <maxPoints value="4"/>
- <maxContours value="1"/>
- <maxCompositePoints value="0"/>
- <maxCompositeContours value="0"/>
<maxZones value="0"/>
<maxTwilightPoints value="0"/>
<maxStorage value="0"/>
@@ -81,7 +66,6 @@
<maxStackElements value="0"/>
<maxSizeOfInstructions value="0"/>
<maxComponentElements value="0"/>
- <maxComponentDepth value="0"/>
</maxp>
<OS_2>
@@ -122,7 +106,7 @@
<achVendID value="UKWN"/>
<fsSelection value="00000000 01000000"/>
<usFirstCharIndex value="32"/>
- <usLastCharIndex value="121"/>
+ <usLastCharIndex value="122"/>
<sTypoAscender value="800"/>
<sTypoDescender value="-200"/>
<sTypoLineGap value="200"/>
@@ -138,20 +122,30 @@
</OS_2>
<hmtx>
- <mtx name=".notdef" width="1000" lsb="0"/>
- <mtx name="R" width="1000" lsb="0"/>
- <mtx name="a" width="1000" lsb="0"/>
- <mtx name="space" width="1000" lsb="0"/>
- <mtx name="y" width="1000" lsb="-1500"/>
+ <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 platformID="3" platEncID="10" format="12" reserved="0" length="64" language="0" nGroups="4">
- <map code="0x20" name="space"/><!-- SPACE -->
- <map code="0x52" name="R"/><!-- LATIN CAPITAL LETTER R -->
- <map code="0x61" name="a"/><!-- LATIN SMALL LETTER A -->
- <map code="0x79" name="y"/><!-- LATIN SMALL LETTER Y -->
+ <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>
@@ -160,47 +154,26 @@
</loca>
<glyf>
-
- <!-- The xMin, yMin, xMax and yMax values
- will be recalculated by the compiler. -->
-
- <TTGlyph name=".notdef"/><!-- contains no outline data -->
-
- <TTGlyph name="R" xMin="0" yMin="0" xMax="5000" yMax="1000">
- <contour>
- <pt x="0" y="0" on="1"/>
- <pt x="0" y="1000" on="1"/>
- <pt x="5000" y="1000" on="1"/>
- <pt x="5000" y="0" on="1"/>
- </contour>
- <instructions/>
- </TTGlyph>
-
- <TTGlyph name="a"/><!-- contains no outline data -->
-
- <TTGlyph name="space"/><!-- contains no outline data -->
-
- <TTGlyph name="y" xMin="-1500" yMin="0" xMax="1000" yMax="1000">
- <contour>
- <pt x="-1500" y="0" on="1"/>
- <pt x="-1500" y="1000" on="1"/>
- <pt x="1000" y="1000" on="1"/>
- <pt x="1000" y="0" on="1"/>
- </contour>
- <instructions/>
- </TTGlyph>
-
+ <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 LineBreakingOverhangsTest
+ 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 LineBreakingOverhangsTest
+ Font for StaticLayoutLineBreakingTest
</namerecord>
<namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
SampleFont-Regular
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
index e0fcf08..b1f8552 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
@@ -22,6 +22,7 @@
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;
@@ -30,49 +31,27 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
-// TODO(lifecycler): Add to presubmit after checking for flakiness.
+@Presubmit
public class ClientTransactionTests {
@Test
- public void testPrepare() {
+ 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 = new ClientTransaction(null /* client */,
+ ClientTransaction transaction = ClientTransaction.obtain(null /* client */,
token /* activityToken */);
transaction.addCallback(callback1);
transaction.addCallback(callback2);
transaction.setLifecycleStateRequest(stateRequest);
- transaction.prepare(clientTransactionHandler);
+ transaction.preExecute(clientTransactionHandler);
- verify(callback1, times(1)).prepare(clientTransactionHandler, token);
- verify(callback2, times(1)).prepare(clientTransactionHandler, token);
- verify(stateRequest, times(1)).prepare(clientTransactionHandler, token);
- }
-
- @Test
- public void testExecute() {
- ClientTransactionItem callback1 = mock(ClientTransactionItem.class);
- ClientTransactionItem callback2 = mock(ClientTransactionItem.class);
- ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
- IBinder token = mock(IBinder.class);
-
- ClientTransaction transaction = new ClientTransaction(null /* client */,
- token /* activityToken */);
- transaction.addCallback(callback1);
- transaction.addCallback(callback2);
- transaction.setLifecycleStateRequest(stateRequest);
-
- ClientTransactionHandler clientTransactionHandler = mock(ClientTransactionHandler.class);
- transaction.prepare(clientTransactionHandler);
- transaction.execute(clientTransactionHandler);
-
- verify(callback1, times(1)).execute(clientTransactionHandler, token);
- verify(callback2, times(1)).execute(clientTransactionHandler, token);
- verify(stateRequest, times(1)).execute(clientTransactionHandler, token);
+ 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..c19a343
--- /dev/null
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -0,0 +1,288 @@
+/*
+ * 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
+// TODO: b/70616950
+//@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
index 9db7550..4b1f2da 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -16,7 +16,9 @@
package android.app.servertransaction;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+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;
@@ -46,6 +48,7 @@
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;
@@ -56,14 +59,13 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/** Test parcelling and unparcelling of transactions and transaction items. */
@RunWith(AndroidJUnit4.class)
@SmallTest
-// TODO(lifecycler): Add to presubmit after checking for flakiness.
+@Presubmit
public class TransactionParcelTests {
private Parcel mParcel;
@@ -76,7 +78,7 @@
@Test
public void testConfigurationChange() {
// Write to parcel
- ConfigurationChangeItem item = new ConfigurationChangeItem(config());
+ ConfigurationChangeItem item = ConfigurationChangeItem.obtain(config());
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -89,7 +91,7 @@
@Test
public void testActivityConfigChange() {
// Write to parcel
- ActivityConfigurationChangeItem item = new ActivityConfigurationChangeItem(config());
+ ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(config());
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -103,7 +105,7 @@
@Test
public void testMoveToDisplay() {
// Write to parcel
- MoveToDisplayItem item = new MoveToDisplayItem(4 /* targetDisplayId */, config());
+ MoveToDisplayItem item = MoveToDisplayItem.obtain(4 /* targetDisplayId */, config());
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -116,7 +118,7 @@
@Test
public void testNewIntent() {
// Write to parcel
- NewIntentItem item = new NewIntentItem(referrerIntentList(), true /* pause */);
+ NewIntentItem item = NewIntentItem.obtain(referrerIntentList(), true /* pause */);
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -129,7 +131,7 @@
@Test
public void testActivityResult() {
// Write to parcel
- ActivityResultItem item = new ActivityResultItem(resultInfoList());
+ ActivityResultItem item = ActivityResultItem.obtain(resultInfoList());
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -142,7 +144,7 @@
@Test
public void testPipModeChange() {
// Write to parcel
- PipModeChangeItem item = new PipModeChangeItem(true /* isInPipMode */, config());
+ PipModeChangeItem item = PipModeChangeItem.obtain(true /* isInPipMode */, config());
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -155,7 +157,7 @@
@Test
public void testMultiWindowModeChange() {
// Write to parcel
- MultiWindowModeChangeItem item = new MultiWindowModeChangeItem(
+ MultiWindowModeChangeItem item = MultiWindowModeChangeItem.obtain(
true /* isInMultiWindowMode */, config());
writeAndPrepareForReading(item);
@@ -170,7 +172,7 @@
@Test
public void testWindowVisibilityChange() {
// Write to parcel
- WindowVisibilityItem item = new WindowVisibilityItem(true /* showWindow */);
+ WindowVisibilityItem item = WindowVisibilityItem.obtain(true /* showWindow */);
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -180,7 +182,7 @@
assertTrue(item.equals(result));
// Check different value
- item = new WindowVisibilityItem(false);
+ item = WindowVisibilityItem.obtain(false);
mParcel = Parcel.obtain();
writeAndPrepareForReading(item);
@@ -194,7 +196,7 @@
@Test
public void testDestroy() {
- DestroyActivityItem item = new DestroyActivityItem(true /* finished */,
+ DestroyActivityItem item = DestroyActivityItem.obtain(true /* finished */,
135 /* configChanges */);
writeAndPrepareForReading(item);
@@ -227,10 +229,10 @@
PersistableBundle persistableBundle = new PersistableBundle();
persistableBundle.putInt("k", 4);
- LaunchActivityItem item = new LaunchActivityItem(intent, ident, activityInfo,
+ LaunchActivityItem item = LaunchActivityItem.obtain(intent, ident, activityInfo,
config(), overrideConfig, compat, referrer, null /* voiceInteractor */,
procState, bundle, persistableBundle, resultInfoList(), referrerIntentList(),
- true /* notResumed */, true /* isForward */, null /* profilerInfo */);
+ true /* isForward */, null /* profilerInfo */);
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -243,8 +245,8 @@
@Test
public void testPause() {
// Write to parcel
- PauseActivityItem item = new PauseActivityItem(true /* finished */, true /* userLeaving */,
- 135 /* configChanges */, true /* dontReport */);
+ PauseActivityItem item = PauseActivityItem.obtain(true /* finished */,
+ true /* userLeaving */, 135 /* configChanges */, true /* dontReport */);
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -257,7 +259,8 @@
@Test
public void testResume() {
// Write to parcel
- ResumeActivityItem item = new ResumeActivityItem(27 /* procState */, true /* isForward */);
+ ResumeActivityItem item = ResumeActivityItem.obtain(27 /* procState */,
+ true /* isForward */);
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -270,7 +273,8 @@
@Test
public void testStop() {
// Write to parcel
- StopActivityItem item = new StopActivityItem(true /* showWindow */, 14 /* configChanges */);
+ StopActivityItem item = StopActivityItem.obtain(true /* showWindow */,
+ 14 /* configChanges */);
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -283,16 +287,17 @@
@Test
public void testClientTransaction() {
// Write to parcel
- WindowVisibilityItem callback1 = new WindowVisibilityItem(true);
- ActivityConfigurationChangeItem callback2 = new ActivityConfigurationChangeItem(config());
+ WindowVisibilityItem callback1 = WindowVisibilityItem.obtain(true);
+ ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain(
+ config());
- StopActivityItem lifecycleRequest = new StopActivityItem(true /* showWindow */,
+ StopActivityItem lifecycleRequest = StopActivityItem.obtain(true /* showWindow */,
78 /* configChanges */);
IApplicationThread appThread = new StubAppThread();
Binder activityToken = new Binder();
- ClientTransaction transaction = new ClientTransaction(appThread, activityToken);
+ ClientTransaction transaction = ClientTransaction.obtain(appThread, activityToken);
transaction.addCallback(callback1);
transaction.addCallback(callback2);
transaction.setLifecycleStateRequest(lifecycleRequest);
@@ -309,13 +314,14 @@
@Test
public void testClientTransactionCallbacksOnly() {
// Write to parcel
- WindowVisibilityItem callback1 = new WindowVisibilityItem(true);
- ActivityConfigurationChangeItem callback2 = new ActivityConfigurationChangeItem(config());
+ WindowVisibilityItem callback1 = WindowVisibilityItem.obtain(true);
+ ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain(
+ config());
IApplicationThread appThread = new StubAppThread();
Binder activityToken = new Binder();
- ClientTransaction transaction = new ClientTransaction(appThread, activityToken);
+ ClientTransaction transaction = ClientTransaction.obtain(appThread, activityToken);
transaction.addCallback(callback1);
transaction.addCallback(callback2);
@@ -331,13 +337,13 @@
@Test
public void testClientTransactionLifecycleOnly() {
// Write to parcel
- StopActivityItem lifecycleRequest = new StopActivityItem(true /* showWindow */,
+ StopActivityItem lifecycleRequest = StopActivityItem.obtain(true /* showWindow */,
78 /* configChanges */);
IApplicationThread appThread = new StubAppThread();
Binder activityToken = new Binder();
- ClientTransaction transaction = new ClientTransaction(appThread, activityToken);
+ ClientTransaction transaction = ClientTransaction.obtain(appThread, activityToken);
transaction.setLifecycleStateRequest(lifecycleRequest);
writeAndPrepareForReading(transaction);
@@ -349,49 +355,6 @@
assertTrue(transaction.equals(result));
}
- private 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;
- }
-
- private 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;
- }
-
- private static Configuration config() {
- Configuration config = new Configuration();
- config.densityDpi = 10;
- config.fontScale = 0.3f;
- config.screenHeightDp = 15;
- config.orientation = ORIENTATION_LANDSCAPE;
- return config;
- }
-
/** 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 */);
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/hardware/display/BrightnessConfigurationTest.java b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
new file mode 100644
index 0000000..bad0d25
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
@@ -0,0 +1,187 @@
+/*
+ * 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.hardware.display;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+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 android.util.Pair;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BrightnessConfigurationTest {
+ private static final float[] LUX_LEVELS = {
+ 0f,
+ 10f,
+ 100f,
+ };
+
+ private static final float[] NITS_LEVELS = {
+ 0.5f,
+ 90f,
+ 100f,
+ };
+
+ @Test
+ public void testSetCurveIsUnmodified() {
+ BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
+ builder.setCurve(LUX_LEVELS, NITS_LEVELS);
+ BrightnessConfiguration config = builder.build();
+ Pair<float[], float[]> curve = config.getCurve();
+ assertArrayEquals(LUX_LEVELS, curve.first, "lux");
+ assertArrayEquals(NITS_LEVELS, curve.second, "nits");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testCurveMustHaveZeroLuxPoint() {
+ BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
+ float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length);
+ lux[0] = 1f;
+ builder.setCurve(lux, NITS_LEVELS);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testCurveMustBeSet() {
+ BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
+ builder.build();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testCurveMustNotHaveNullArrays() {
+ BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
+ builder.setCurve(null, null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testCurveMustNotHaveEmptyArrays() {
+ BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
+ builder.setCurve(new float[0], new float[0]);
+ }
+
+ @Test
+ public void testCurveMustNotHaveArraysOfDifferentLengths() {
+ assertThrows(IllegalArgumentException.class, () -> {
+ BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
+ float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length + 1);
+ lux[lux.length - 1] = lux[lux.length - 2] + 1;
+ boolean exceptionThrown = false;
+ builder.setCurve(lux, NITS_LEVELS);
+ });
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
+ float[] nits = Arrays.copyOf(NITS_LEVELS, NITS_LEVELS.length + 1);
+ nits[nits.length - 1] = nits[nits.length - 2] + 1;
+ builder.setCurve(LUX_LEVELS, nits);
+ });
+ }
+
+ @Test
+ public void testCurvesMustNotContainNaN() {
+ assertThrows(IllegalArgumentException.class, () -> {
+ float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length);
+ lux[lux.length - 1] = Float.NaN;
+ BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
+ builder.setCurve(lux, NITS_LEVELS);
+ });
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ float[] nits = Arrays.copyOf(NITS_LEVELS, NITS_LEVELS.length);
+ nits[nits.length - 1] = Float.NaN;
+ BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
+ builder.setCurve(LUX_LEVELS, nits);
+ });
+ }
+
+
+ @Test
+ public void testParceledConfigIsEquivalent() {
+ BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
+ builder.setCurve(LUX_LEVELS, NITS_LEVELS);
+ BrightnessConfiguration config = builder.build();
+ Parcel p = Parcel.obtain();
+ p.writeParcelable(config, 0 /*flags*/);
+ p.setDataPosition(0);
+ BrightnessConfiguration newConfig =
+ p.readParcelable(BrightnessConfiguration.class.getClassLoader());
+ assertEquals(config, newConfig);
+ }
+
+ @Test
+ public void testEquals() {
+ BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
+ builder.setCurve(LUX_LEVELS, NITS_LEVELS);
+ BrightnessConfiguration baseConfig = builder.build();
+
+ builder = new BrightnessConfiguration.Builder();
+ builder.setCurve(LUX_LEVELS, NITS_LEVELS);
+ BrightnessConfiguration identicalConfig = builder.build();
+ assertEquals(baseConfig, identicalConfig);
+ assertEquals("hashCodes must be equal for identical configs",
+ baseConfig.hashCode(), identicalConfig.hashCode());
+
+ float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length);
+ lux[lux.length - 1] = lux[lux.length - 1] * 2;
+ builder = new BrightnessConfiguration.Builder();
+ builder.setCurve(lux, NITS_LEVELS);
+ BrightnessConfiguration luxDifferConfig = builder.build();
+ assertNotEquals(baseConfig, luxDifferConfig);
+
+ float[] nits = Arrays.copyOf(NITS_LEVELS, NITS_LEVELS.length);
+ nits[nits.length - 1] = nits[nits.length - 1] * 2;
+ builder = new BrightnessConfiguration.Builder();
+ builder.setCurve(LUX_LEVELS, nits);
+ BrightnessConfiguration nitsDifferConfig = builder.build();
+ assertNotEquals(baseConfig, nitsDifferConfig);
+ }
+
+ private static void assertArrayEquals(float[] expected, float[] actual, String name) {
+ assertEquals("Expected " + name + " arrays to be the same length!",
+ expected.length, actual.length);
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals("Expected " + name + " arrays to be equivalent when value " + i
+ + "differs", expected[i], actual[i], 0.01 /*tolerance*/);
+ }
+ }
+
+ private interface ExceptionRunnable {
+ void run() throws Exception;
+ }
+
+ private static void assertThrows(Class<? extends Throwable> exceptionClass,
+ ExceptionRunnable r) {
+ try {
+ r.run();
+ } catch (Throwable e) {
+ assertTrue("Expected exception type " + exceptionClass.getName() + " but got "
+ + e.getClass().getName(), exceptionClass.isAssignableFrom(e.getClass()));
+ return;
+ }
+ fail("Expected exception type " + exceptionClass.getName()
+ + ", but no exception was thrown");
+ }
+}
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 454d209..b03f054 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,
@@ -195,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,
@@ -231,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,
@@ -366,6 +367,7 @@
Settings.Global.ENABLE_GPU_DEBUG_LAYERS,
Settings.Global.GPU_DEBUG_APP,
Settings.Global.GPU_DEBUG_LAYERS,
+ Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
Settings.Global.NETWORK_ACCESS_TIMEOUT_MS,
Settings.Global.WARNING_TEMPERATURE,
Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY,
@@ -418,7 +420,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/BidiFormatterTest.java b/core/tests/coretests/src/android/text/BidiFormatterTest.java
index 14705ad..1b936c7 100644
--- a/core/tests/coretests/src/android/text/BidiFormatterTest.java
+++ b/core/tests/coretests/src/android/text/BidiFormatterTest.java
@@ -18,12 +18,14 @@
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.Test;
import org.junit.runner.RunWith;
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BidiFormatterTest {
diff --git a/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java b/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
index 08e1b5b..c69f4f5 100644
--- a/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
+++ b/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -33,6 +34,7 @@
* Requires disabling access checks in the vm since this calls package-private APIs.
*
*/
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DynamicLayoutBlocksTest {
diff --git a/core/tests/coretests/src/android/text/DynamicLayoutTest.java b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
index 639cefb..aa9aed8 100644
--- a/core/tests/coretests/src/android/text/DynamicLayoutTest.java
+++ b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
@@ -26,6 +26,7 @@
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.style.ReplacementSpan;
@@ -33,6 +34,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DynamicLayoutTest {
diff --git a/core/tests/coretests/src/android/text/LayoutTest.java b/core/tests/coretests/src/android/text/LayoutTest.java
index 9cf8e1e..2448b0b 100644
--- a/core/tests/coretests/src/android/text/LayoutTest.java
+++ b/core/tests/coretests/src/android/text/LayoutTest.java
@@ -29,6 +29,7 @@
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.Layout.Alignment;
@@ -42,6 +43,7 @@
import java.util.List;
import java.util.Locale;
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class LayoutTest {
diff --git a/core/tests/coretests/src/android/text/LineBreakingOverhangsTest.java b/core/tests/coretests/src/android/text/LineBreakingOverhangsTest.java
deleted file mode 100644
index 4f18b0b..0000000
--- a/core/tests/coretests/src/android/text/LineBreakingOverhangsTest.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open 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 android.annotation.NonNull;
-import android.annotation.Nullable;
-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 LineBreakingOverhangsTest {
- private static final int EM = 100; // Make 1em == 100px.
- private static final TextPaint sTextPaint = new TextPaint();
-
- static {
- // The test font has following coverage and overhangs.
- // All the characters have a width of 1em.
- // space: no overhangs
- // R: 4em overhang on the right
- // a: no overhang
- // y: 1.5em overhang on the left
- sTextPaint.setTypeface(Typeface.createFromAsset(
- InstrumentationRegistry.getTargetContext().getAssets(),
- "fonts/LineBreakingOverhangsTestFont.ttf"));
- sTextPaint.setTextSize(EM);
- }
-
- private static void layout(@NonNull CharSequence source, @NonNull int[] breaks, double width,
- @Nullable int[] leftPadding, @Nullable int[] rightPadding) {
- layout(source, breaks, width, leftPadding, rightPadding, null /* indents */);
- }
-
- private static void layout(@NonNull CharSequence source, @NonNull int[] breaks, double width,
- @Nullable int[] leftPadding, @Nullable int[] rightPadding, @Nullable int[] indents) {
- final StaticLayout staticLayout = StaticLayout.Builder
- .obtain(source, 0, source.length(), sTextPaint, (int) width)
- .setAvailablePaddings(leftPadding, rightPadding)
- .setIndents(indents, indents)
- .build();
-
- final int lineCount = breaks.length + 1;
- assertEquals("Number of lines", lineCount, staticLayout.getLineCount());
-
- for (int line = 0; line < lineCount; line++) {
- final int lineStart = staticLayout.getLineStart(line);
- final int lineEnd = staticLayout.getLineEnd(line);
-
- if (line == 0) {
- assertEquals("Line start for first line", 0, lineStart);
- } else {
- assertEquals("Line start for line " + line, breaks[line - 1], lineStart);
- }
-
- if (line == lineCount - 1) {
- assertEquals("Line end for last line", source.length(), lineEnd);
- } else {
- assertEquals("Line end for line " + line, breaks[line], lineEnd);
- }
- }
- }
-
- private static final int[] NO_BREAK = new int[] {};
-
- private static final int[] NO_PADDING = null;
- // Maximum needed for left side of 'y'.
- private static final int[] FULL_LEFT_PADDING = new int[] {(int) (1.5 * EM)};
- // Maximum padding needed for right side of 'R'.
- private static final int[] FULL_RIGHT_PADDING = new int[] {4 * EM};
-
- private static final int[] ONE_EM_PADDING = new int[] {1 * EM};
- private static final int[] HALF_EM_PADDING = new int[] {(int) (0.5 * EM)};
- private static final int[] QUARTER_EM_PADDING = new int[] {(int) (0.25 * EM)};
-
- @Test
- public void testRightOverhang() {
- // The advance of "aaa R" is 5em, but the right-side overhang of 'R' would need 4em more, so
- // we break the line if there's not enough overhang.
-
- // Enough right padding, so the whole line fits in 5em.
- layout("aaa R", NO_BREAK, 5 * EM, NO_PADDING, FULL_RIGHT_PADDING);
-
- // No right padding, so we'd need 9em to fit the advance and the right padding of 'R'.
- layout("aaa R", new int[] {4}, 8.9 * EM, NO_PADDING, NO_PADDING);
- layout("aaa R", NO_BREAK, 9 * EM, NO_PADDING, NO_PADDING);
-
- // 1em of right padding means we can fit the string in 8em.
- layout("aaa R", new int[] {4}, 7.9 * EM, NO_PADDING, ONE_EM_PADDING);
- layout("aaa R", NO_BREAK, 8 * EM, NO_PADDING, ONE_EM_PADDING);
- }
-
- @Test
- public void testLeftOverhang() {
- // The advance of "y a" is 3em, but the left-side overhang of 'y' would need 1.5em more, so
- // we break the line if there's not enough overhang.
-
- // Enough left padding, so the whole line fits in 3em.
- layout("y a", NO_BREAK, 3 * EM, FULL_LEFT_PADDING, NO_PADDING);
-
- // No right padding, so we'd need 4.5em to fit the advance and the left padding of 'y'.
- layout("y a", new int[] {2}, 4.4 * EM, NO_PADDING, NO_PADDING);
- layout("y a", NO_BREAK, 4.5 * EM, NO_PADDING, NO_PADDING);
-
- // 1em of left padding means we can fit the string in 3.5em.
- layout("y a", new int[] {2}, 3.4 * EM, ONE_EM_PADDING, NO_PADDING);
- layout("y a", NO_BREAK, 3.5 * EM, ONE_EM_PADDING, NO_PADDING);
- }
-
- @Test
- public void testBothSidesOverhang() {
- // The advance of "y a R" is 5em, but the left-side overhang of 'y' would need 1.5em more,
- // and the right side overhang or 'R' would need 4em more, so we break the line if there's
- // not enough overhang.
-
- // Enough padding, so the whole line fits in 5em.
- layout("y a R", NO_BREAK, 5 * EM, FULL_LEFT_PADDING, FULL_RIGHT_PADDING);
-
- // No padding, so we'd need 10.5em to fit the advance and the paddings.
- layout("y a R", new int[] {4}, 10.4 * EM, NO_PADDING, NO_PADDING);
- layout("y a R", NO_BREAK, 10.5 * EM, NO_PADDING, NO_PADDING);
-
- // 1em of padding on each side means we can fit the string in 8.5em.
- layout("y a R", new int[] {4}, 8.4 * EM, ONE_EM_PADDING, ONE_EM_PADDING);
- layout("y a R", NO_BREAK, 8.5 * EM, ONE_EM_PADDING, ONE_EM_PADDING);
- }
-
- @Test
- public void testIndentsDontAffectPaddings() {
- // This is identical to the previous test, except that it applies wide indents of 4em on
- // each side and thus needs an extra 8em of width. This test makes sure that indents and
- // paddings are independent.
- final int[] indents = new int[] {4 * EM};
- final int indentAdj = 8 * EM;
-
- // Enough padding, so the whole line fits in 5em.
- layout("y a R", NO_BREAK, 5 * EM + indentAdj, FULL_LEFT_PADDING, FULL_RIGHT_PADDING,
- indents);
-
- // No padding, so we'd need 10.5em to fit the advance and the paddings.
- layout("y a R", new int[] {4}, 10.4 * EM + indentAdj, NO_PADDING, NO_PADDING, indents);
- layout("y a R", NO_BREAK, 10.5 * EM + indentAdj, NO_PADDING, NO_PADDING, indents);
-
- // 1em of padding on each side means we can fit the string in 8.5em.
- layout("y a R", new int[] {4}, 8.4 * EM + indentAdj, ONE_EM_PADDING, ONE_EM_PADDING,
- indents);
- layout("y a R", NO_BREAK, 8.5 * EM + indentAdj, ONE_EM_PADDING, ONE_EM_PADDING, indents);
- }
-}
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/text/PackedIntVectorTest.java b/core/tests/coretests/src/android/text/PackedIntVectorTest.java
index 9df0f89..d9dc6fc 100644
--- a/core/tests/coretests/src/android/text/PackedIntVectorTest.java
+++ b/core/tests/coretests/src/android/text/PackedIntVectorTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
+import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -27,6 +28,7 @@
/**
* PackedIntVectorTest tests the features of android.util.PackedIntVector.
*/
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class PackedIntVectorTest {
diff --git a/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java b/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java
index 04a486e..f1a730a 100644
--- a/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java
+++ b/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java
@@ -20,13 +20,18 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.text.style.BulletSpan;
import android.text.style.QuoteSpan;
import android.text.style.SubscriptSpan;
import android.text.style.UnderlineSpan;
import org.junit.Test;
+import org.junit.runner.RunWith;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
public class SpannableStringBuilderTest extends SpannableTest {
protected Spannable newSpannableWithText(String text) {
diff --git a/core/tests/coretests/src/android/text/SpannableTest.java b/core/tests/coretests/src/android/text/SpannableTest.java
index 5ed6250..307ac62 100644
--- a/core/tests/coretests/src/android/text/SpannableTest.java
+++ b/core/tests/coretests/src/android/text/SpannableTest.java
@@ -16,14 +16,16 @@
package android.text;
-import android.support.test.filters.MediumTest;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.test.MoreAsserts;
import org.junit.Test;
import org.junit.runner.RunWith;
-@MediumTest
+@Presubmit
+@SmallTest
@RunWith(AndroidJUnit4.class)
public abstract class SpannableTest {
diff --git a/core/tests/coretests/src/android/text/SpannedTest.java b/core/tests/coretests/src/android/text/SpannedTest.java
index 60cddb08..5737571 100644
--- a/core/tests/coretests/src/android/text/SpannedTest.java
+++ b/core/tests/coretests/src/android/text/SpannedTest.java
@@ -20,6 +20,7 @@
import android.graphics.Typeface;
import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.style.CharacterStyle;
@@ -33,6 +34,7 @@
/**
* SpannedTest tests some features of Spanned
*/
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SpannedTest {
diff --git a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
index 8092203..bf0d427 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
@@ -18,6 +18,7 @@
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 android.util.Log;
@@ -28,6 +29,7 @@
/**
* Quick check of native bidi implementation.
*/
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class StaticLayoutBidiTest {
diff --git a/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java b/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
index e0b4776..5cf5426 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
@@ -18,16 +18,19 @@
import static org.junit.Assert.fail;
+import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.Layout.Directions;
import android.text.StaticLayoutTest.LayoutBuilder;
-import java.util.Arrays;
-import java.util.Formatter;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
+import java.util.Formatter;
+
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class StaticLayoutDirectionsTest {
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java
index 078ed76..f4514b5 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java
@@ -24,6 +24,7 @@
import android.graphics.Canvas;
import android.graphics.Paint.FontMetricsInt;
import android.os.LocaleList;
+import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.Layout.Alignment;
@@ -43,6 +44,7 @@
/**
* Tests StaticLayout vertical metrics behavior.
*/
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class StaticLayoutTest {
diff --git a/core/tests/coretests/src/android/text/TextLayoutTest.java b/core/tests/coretests/src/android/text/TextLayoutTest.java
index 8963189..24020ce 100644
--- a/core/tests/coretests/src/android/text/TextLayoutTest.java
+++ b/core/tests/coretests/src/android/text/TextLayoutTest.java
@@ -16,6 +16,7 @@
package android.text;
+import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -23,6 +24,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TextLayoutTest {
diff --git a/core/tests/coretests/src/android/text/TextLineTest.java b/core/tests/coretests/src/android/text/TextLineTest.java
index f8d6884..d9c09c8 100644
--- a/core/tests/coretests/src/android/text/TextLineTest.java
+++ b/core/tests/coretests/src/android/text/TextLineTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.filters.Suppress;
import android.support.test.runner.AndroidJUnit4;
@@ -26,6 +27,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TextLineTest {
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index 79619d9a..e70b841 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -25,6 +25,7 @@
import static org.junit.Assert.fail;
import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
import android.support.test.filters.LargeTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -46,6 +47,7 @@
/**
* TextUtilsTest tests {@link TextUtils}.
*/
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TextUtilsTest {
diff --git a/core/tests/coretests/src/android/text/VariationParserTest.java b/core/tests/coretests/src/android/text/VariationParserTest.java
index ec2c96c..fbd2412 100644
--- a/core/tests/coretests/src/android/text/VariationParserTest.java
+++ b/core/tests/coretests/src/android/text/VariationParserTest.java
@@ -20,12 +20,14 @@
import static org.junit.Assert.fail;
import android.graphics.fonts.FontVariationAxis;
+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;
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class VariationParserTest {
diff --git a/core/tests/coretests/src/android/text/format/DateFormatTest.java b/core/tests/coretests/src/android/text/format/DateFormatTest.java
index 0f08d18..9000ed0 100644
--- a/core/tests/coretests/src/android/text/format/DateFormatTest.java
+++ b/core/tests/coretests/src/android/text/format/DateFormatTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -27,6 +28,7 @@
import java.util.Locale;
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DateFormatTest {
diff --git a/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
index f21c929..f8e3b4d 100644
--- a/core/tests/coretests/src/android/text/format/DateUtilsTest.java
+++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
@@ -21,6 +21,7 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.LocaleList;
+import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -35,6 +36,7 @@
import java.util.Locale;
import java.util.TimeZone;
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DateUtilsTest {
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index dee51dc..2d94016 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -189,7 +189,7 @@
// Make sure it works on different locales.
setLocale(new Locale("ru", "RU"));
- assertEquals("1 мин", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
+ assertEquals("1 мин.", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
mContext, 1 * SECOND));
}
diff --git a/core/tests/coretests/src/android/text/format/TimeTest.java b/core/tests/coretests/src/android/text/format/TimeTest.java
index 8983d15..d563f2e 100644
--- a/core/tests/coretests/src/android/text/format/TimeTest.java
+++ b/core/tests/coretests/src/android/text/format/TimeTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.filters.Suppress;
import android.support.test.runner.AndroidJUnit4;
@@ -29,6 +30,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TimeTest {
diff --git a/core/tests/coretests/src/android/text/method/BackspaceTest.java b/core/tests/coretests/src/android/text/method/BackspaceTest.java
index 8b5cc60..df4609f 100644
--- a/core/tests/coretests/src/android/text/method/BackspaceTest.java
+++ b/core/tests/coretests/src/android/text/method/BackspaceTest.java
@@ -16,6 +16,7 @@
package android.text.method;
+import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -24,6 +25,7 @@
import android.view.KeyEvent;
import android.widget.EditText;
import android.widget.TextView.BufferType;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,6 +36,8 @@
* Only contains edge cases. For normal cases, see {@see android.text.method.cts.BackspaceTest}.
* TODO: introduce test cases for surrogate pairs and replacement span.
*/
+
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BackspaceTest {
diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
index c3a5f80..15dbbc8 100644
--- a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
+++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
@@ -16,6 +16,7 @@
package android.text.method;
+import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -35,6 +36,7 @@
* Only contains edge cases. For normal cases, see {@see android.text.method.cts.ForwardDeleteTest}.
* TODO: introduce test cases for surrogate pairs and replacement span.
*/
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ForwardDeleteTest {
diff --git a/core/tests/coretests/src/android/text/method/WordIteratorTest.java b/core/tests/coretests/src/android/text/method/WordIteratorTest.java
index d1f4f7e..6845863 100644
--- a/core/tests/coretests/src/android/text/method/WordIteratorTest.java
+++ b/core/tests/coretests/src/android/text/method/WordIteratorTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -31,6 +32,7 @@
import java.util.Locale;
// TODO(Bug: 24062099): Add more tests for non-ascii text.
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class WordIteratorTest {
diff --git a/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java b/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java
index e5c4b82..3d7e5ba 100644
--- a/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java
+++ b/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java
@@ -19,6 +19,7 @@
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 android.text.SpannableString;
@@ -29,7 +30,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class UnderlineSpanTest {
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/util/ScrollViewScenario.java b/core/tests/coretests/src/android/util/ScrollViewScenario.java
index b5140e3..e9eb978 100644
--- a/core/tests/coretests/src/android/util/ScrollViewScenario.java
+++ b/core/tests/coretests/src/android/util/ScrollViewScenario.java
@@ -269,6 +269,6 @@
mScrollView.setSmoothScrollingEnabled(false);
setContentView(mScrollView);
- mScrollView.restoreDefaultFocus();
+ mScrollView.post(() -> mScrollView.restoreDefaultFocus());
}
}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
index 8a5fc2d..c1b2309 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
@@ -24,6 +24,7 @@
import android.os.RemoteException;
import android.support.test.runner.AndroidJUnit4;
+import libcore.util.EmptyArray;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,7 +74,7 @@
List<AccessibilityNodeInfo> mInfosToReturn;
@Override
- public boolean findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
+ public String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
long accessibilityNodeId, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
Bundle arguments) {
@@ -82,7 +83,7 @@
} catch (RemoteException e) {
throw new RuntimeException(e);
}
- return true;
+ return EmptyArray.STRING;
}
}
}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index d3bbee7..44b1f08 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -31,35 +31,35 @@
public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceConnection.Stub {
public void setServiceInfo(AccessibilityServiceInfo info) {}
- public boolean findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
+ public String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
long accessibilityNodeId, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
Bundle arguments) {
- return false;
+ return null;
}
- public boolean findAccessibilityNodeInfosByText(int accessibilityWindowId,
+ public String[] findAccessibilityNodeInfosByText(int accessibilityWindowId,
long accessibilityNodeId, String text, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long threadId) {
- return false;
+ return null;
}
- public boolean findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
+ public String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
long accessibilityNodeId, String viewId, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long threadId) {
- return false;
+ return null;
}
- public boolean findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType,
+ public String[] findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType,
int interactionId, IAccessibilityInteractionConnectionCallback callback,
long threadId) {
- return false;
+ return null;
}
- public boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction,
+ public String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction,
int interactionId, IAccessibilityInteractionConnectionCallback callback,
long threadId) {
- return false;
+ return null;
}
public boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId,
diff --git a/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
index e0664d9..0fd0136 100644
--- a/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
@@ -16,21 +16,33 @@
package android.view.inputmethod;
-import android.graphics.Matrix;
-import android.graphics.RectF;
-import android.os.Parcel;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.text.TextUtils;
-import android.view.inputmethod.CursorAnchorInfo.Builder;
-
-import java.util.Objects;
-
import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
import static android.view.inputmethod.CursorAnchorInfo.FLAG_IS_RTL;
-public class CursorAnchorInfoTest extends InstrumentationTestCase {
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.TextUtils;
+import android.view.inputmethod.CursorAnchorInfo.Builder;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Objects;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CursorAnchorInfoTest {
+ private static final float EPSILON = 0.0000001f;
+
private static final RectF[] MANY_BOUNDS = new RectF[] {
new RectF(101.0f, 201.0f, 301.0f, 401.0f),
new RectF(102.0f, 202.0f, 302.0f, 402.0f),
@@ -74,7 +86,7 @@
FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL,
};
- @SmallTest
+ @Test
public void testBuilder() throws Exception {
final int SELECTION_START = 30;
final int SELECTION_END = 40;
@@ -109,10 +121,10 @@
assertEquals(COMPOSING_TEXT_START, info.getComposingTextStart());
assertTrue(TextUtils.equals(COMPOSING_TEXT, info.getComposingText()));
assertEquals(INSERTION_MARKER_FLAGS, info.getInsertionMarkerFlags());
- assertEquals(INSERTION_MARKER_HORIZONTAL, info.getInsertionMarkerHorizontal());
- assertEquals(INSERTION_MARKER_TOP, info.getInsertionMarkerTop());
- assertEquals(INSERTION_MARKER_BASELINE, info.getInsertionMarkerBaseline());
- assertEquals(INSERTION_MARKER_BOTOM, info.getInsertionMarkerBottom());
+ assertEquals(INSERTION_MARKER_HORIZONTAL, info.getInsertionMarkerHorizontal(), EPSILON);
+ assertEquals(INSERTION_MARKER_TOP, info.getInsertionMarkerTop(), EPSILON);
+ assertEquals(INSERTION_MARKER_BASELINE, info.getInsertionMarkerBaseline(), EPSILON);
+ assertEquals(INSERTION_MARKER_BOTOM, info.getInsertionMarkerBottom(), EPSILON);
assertEquals(TRANSFORM_MATRIX, info.getMatrix());
for (int i = 0; i < MANY_BOUNDS.length; i++) {
final RectF expectedBounds = MANY_BOUNDS[i];
@@ -134,10 +146,10 @@
assertEquals(COMPOSING_TEXT_START, info2.getComposingTextStart());
assertTrue(TextUtils.equals(COMPOSING_TEXT, info2.getComposingText()));
assertEquals(INSERTION_MARKER_FLAGS, info2.getInsertionMarkerFlags());
- assertEquals(INSERTION_MARKER_HORIZONTAL, info2.getInsertionMarkerHorizontal());
- assertEquals(INSERTION_MARKER_TOP, info2.getInsertionMarkerTop());
- assertEquals(INSERTION_MARKER_BASELINE, info2.getInsertionMarkerBaseline());
- assertEquals(INSERTION_MARKER_BOTOM, info2.getInsertionMarkerBottom());
+ assertEquals(INSERTION_MARKER_HORIZONTAL, info2.getInsertionMarkerHorizontal(), EPSILON);
+ assertEquals(INSERTION_MARKER_TOP, info2.getInsertionMarkerTop(), EPSILON);
+ assertEquals(INSERTION_MARKER_BASELINE, info2.getInsertionMarkerBaseline(), EPSILON);
+ assertEquals(INSERTION_MARKER_BOTOM, info2.getInsertionMarkerBottom(), EPSILON);
assertEquals(TRANSFORM_MATRIX, info2.getMatrix());
for (int i = 0; i < MANY_BOUNDS.length; i++) {
final RectF expectedBounds = MANY_BOUNDS[i];
@@ -161,10 +173,10 @@
assertEquals(COMPOSING_TEXT_START, info3.getComposingTextStart());
assertTrue(TextUtils.equals(COMPOSING_TEXT, info3.getComposingText()));
assertEquals(INSERTION_MARKER_FLAGS, info3.getInsertionMarkerFlags());
- assertEquals(INSERTION_MARKER_HORIZONTAL, info3.getInsertionMarkerHorizontal());
- assertEquals(INSERTION_MARKER_TOP, info3.getInsertionMarkerTop());
- assertEquals(INSERTION_MARKER_BASELINE, info3.getInsertionMarkerBaseline());
- assertEquals(INSERTION_MARKER_BOTOM, info3.getInsertionMarkerBottom());
+ assertEquals(INSERTION_MARKER_HORIZONTAL, info3.getInsertionMarkerHorizontal(), EPSILON);
+ assertEquals(INSERTION_MARKER_TOP, info3.getInsertionMarkerTop(), EPSILON);
+ assertEquals(INSERTION_MARKER_BASELINE, info3.getInsertionMarkerBaseline(), EPSILON);
+ assertEquals(INSERTION_MARKER_BOTOM, info3.getInsertionMarkerBottom(), EPSILON);
assertEquals(TRANSFORM_MATRIX, info3.getMatrix());
for (int i = 0; i < MANY_BOUNDS.length; i++) {
final RectF expectedBounds = MANY_BOUNDS[i];
@@ -187,10 +199,10 @@
assertEquals(-1, uninitializedInfo.getComposingTextStart());
assertNull(uninitializedInfo.getComposingText());
assertEquals(0, uninitializedInfo.getInsertionMarkerFlags());
- assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerHorizontal());
- assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerTop());
- assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBaseline());
- assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBottom());
+ assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerHorizontal(), EPSILON);
+ assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerTop(), EPSILON);
+ assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBaseline(), EPSILON);
+ assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBottom(), EPSILON);
assertEquals(Matrix.IDENTITY_MATRIX, uninitializedInfo.getMatrix());
}
@@ -199,7 +211,7 @@
assertFalse(Objects.equals(reference, actual));
}
- @SmallTest
+ @Test
public void testEquality() throws Exception {
final Matrix MATRIX1 = new Matrix();
MATRIX1.setTranslate(10.0f, 20.0f);
@@ -357,7 +369,7 @@
INSERTION_MARKER_FLAGS2).build());
}
- @SmallTest
+ @Test
public void testMatrixIsCopied() throws Exception {
final Matrix MATRIX1 = new Matrix();
MATRIX1.setTranslate(10.0f, 20.0f);
@@ -385,7 +397,7 @@
assertEquals(MATRIX2, secondInstance.getMatrix());
}
- @SmallTest
+ @Test
public void testMatrixIsRequired() throws Exception {
final int SELECTION_START = 30;
final int SELECTION_END = 40;
@@ -434,7 +446,7 @@
}
}
- @SmallTest
+ @Test
public void testBuilderAddCharacterBounds() throws Exception {
// A negative index should be rejected.
try {
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/inputmethod/InputMethodSubtypeArrayTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
index a339f61..8df1848 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
@@ -16,16 +16,24 @@
package android.view.inputmethod;
+import static org.junit.Assert.assertEquals;
+
import android.os.Parcel;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.ArrayList;
-public class InputMethodSubtypeArrayTest extends InstrumentationTestCase {
- @SmallTest
- public void testInstanciate() throws Exception {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputMethodSubtypeArrayTest {
+
+ @Test
+ public void testInstantiate() throws Exception {
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
subtypes.add(createDummySubtype(0, "en_US"));
subtypes.add(createDummySubtype(1, "en_US"));
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
index d203465..c76359e 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
@@ -16,15 +16,26 @@
package android.view.inputmethod;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
import android.os.Parcel;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.Locale;
import java.util.Objects;
-public class InputMethodSubtypeTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputMethodSubtypeTest {
public void verifyLocale(final String localeString) {
// InputMethodSubtype#getLocale() returns exactly the same string that is passed to the
@@ -48,7 +59,7 @@
cloneViaParcel(cloneViaParcel(createDummySubtype(localeString))).hashCode());
}
- @SmallTest
+ @Test
public void testLocaleObj_locale() {
final InputMethodSubtype usSubtype = createDummySubtype("en_US");
Locale localeObject = usSubtype.getLocaleObject();
@@ -59,7 +70,7 @@
assertTrue(localeObject == usSubtype.getLocaleObject());
}
- @SmallTest
+ @Test
public void testLocaleObj_languageTag() {
final InputMethodSubtype usSubtype = createDummySubtypeUsingLanguageTag("en-US");
Locale localeObject = usSubtype.getLocaleObject();
@@ -71,7 +82,7 @@
assertTrue(localeObject == usSubtype.getLocaleObject());
}
- @SmallTest
+ @Test
public void testLocaleObj_emptyLocale() {
final InputMethodSubtype emptyLocaleSubtype = createDummySubtype("");
assertNull(emptyLocaleSubtype.getLocaleObject());
@@ -80,7 +91,7 @@
assertNull(emptyLocaleSubtype.getLocaleObject());
}
- @SmallTest
+ @Test
public void testLocaleString() throws Exception {
// The locale string in InputMethodSubtype has accepted an arbitrary text actually,
// regardless of the validity of the text as a locale string.
@@ -95,7 +106,7 @@
verifyLocale("fil_PH");
}
- @SmallTest
+ @Test
public void testDeprecatedLocaleString() throws Exception {
// Make sure "iw" is not automatically replaced with "he".
final InputMethodSubtype subtypeIw = createDummySubtype("iw");
diff --git a/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java b/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
index f9fa017..8c96b58 100644
--- a/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
@@ -16,15 +16,25 @@
package android.view.inputmethod;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
import android.graphics.RectF;
import android.os.Parcel;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.Objects;
-public class SparseRectFArrayTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SparseRectFArrayTest {
// A test data for {@link SparseRectFArray}. null represents the gap of indices.
private static final RectF[] MANY_RECTS = new RectF[] {
null,
@@ -49,7 +59,7 @@
new RectF(118.0f, 218.0f, 318.0f, 418.0f),
};
- @SmallTest
+ @Test
public void testBuilder() throws Exception {
final RectF TEMP_RECT = new RectF(10.0f, 20.0f, 30.0f, 40.0f);
final int TEMP_FLAGS = 0x1234;
@@ -128,7 +138,7 @@
assertNull(builder.build().get(0));
}
- @SmallTest
+ @Test
public void testEquality() throws Exception {
// Empty array should be equal.
assertEqualRects(new SparseRectFArrayBuilder().build(),
@@ -225,7 +235,7 @@
.build());
}
- @SmallTest
+ @Test
public void testBuilderAppend() throws Exception {
// Key should be appended in ascending order.
try {
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..13d6749 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
@@ -16,11 +16,15 @@
package com.android.internal.inputmethod;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
@@ -28,16 +32,22 @@
import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ControllerImpl;
import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-public class InputMethodSubtypeSwitchingControllerTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputMethodSubtypeSwitchingControllerTest {
private static final String DUMMY_PACKAGE_NAME = "dummy package name";
private static final String DUMMY_IME_LABEL = "dummy ime label";
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 +85,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 +121,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);
}
@@ -188,7 +199,7 @@
controller.onUserActionLocked(subtypeListItem.mImi, subtype);
}
- @SmallTest
+ @Test
public void testControllerImpl() throws Exception {
final List<ImeSubtypeListItem> disabledItems = createDisabledImeSubtypes();
final ImeSubtypeListItem disabledIme_en_US = disabledItems.get(0);
@@ -248,7 +259,7 @@
disabledSubtypeUnawareIme, null, null);
}
- @SmallTest
+ @Test
public void testControllerImplWithUserAction() throws Exception {
final List<ImeSubtypeListItem> enabledItems = createEnabledImeSubtypes();
final ImeSubtypeListItem latinIme_en_US = enabledItems.get(0);
@@ -329,7 +340,7 @@
switchingUnawarelatinIme_en_UK, switchUnawareJapaneseIme_ja_JP);
}
- @SmallTest
+ @Test
public void testImeSubtypeListItem() throws Exception {
final List<ImeSubtypeListItem> items = new ArrayList<>();
addDummyImeSubtypeListItems(items, "LatinIme", "LatinIme",
@@ -358,7 +369,7 @@
assertFalse(item_EN_US.mIsSystemLocale);
}
- @SmallTest
+ @Test
public void testImeSubtypeListComparator() throws Exception {
{
final List<ImeSubtypeListItem> items = Arrays.asList(
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
index d89dc63..e6ac682 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
@@ -16,38 +16,52 @@
package com.android.internal.inputmethod;
+import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR;
+import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_VIEW_HAS_FOCUS;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.in;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.core.Is.is;
+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 android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.os.Build;
import android.os.LocaleList;
import android.os.Parcel;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
import android.view.inputmethod.InputMethodSubtype;
+import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.isIn;
-import static org.hamcrest.Matchers.not;
-
-public class InputMethodUtilsTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputMethodUtilsTest {
private static final boolean IS_AUX = true;
private static final boolean IS_DEFAULT = true;
private static final boolean IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE = true;
private static final boolean IS_ASCII_CAPABLE = true;
private static final boolean IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE = true;
- private static final boolean IS_SYSTEM_READY = true;
private static final Locale LOCALE_EN = new Locale("en");
private static final Locale LOCALE_EN_US = new Locale("en", "US");
private static final Locale LOCALE_EN_GB = new Locale("en", "GB");
@@ -77,7 +91,7 @@
private static final String EXTRA_VALUE_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE =
"EnabledWhenDefaultIsNotAsciiCapable";
- @SmallTest
+ @Test
public void testVoiceImes() throws Exception {
// locale: en_US
assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_US,
@@ -101,7 +115,7 @@
"DummyNonDefaultAutoVoiceIme1");
}
- @SmallTest
+ @Test
public void testKeyboardImes() throws Exception {
// locale: en_US
assertDefaultEnabledImes(getSamplePreinstalledImes("en-rUS"), LOCALE_EN_US,
@@ -136,7 +150,7 @@
"com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
}
- @SmallTest
+ @Test
public void testParcelable() throws Exception {
final ArrayList<InputMethodInfo> originalList = getSamplePreinstalledImes("en-rUS");
final List<InputMethodInfo> clonedList = cloneViaParcel(originalList);
@@ -153,7 +167,7 @@
}
}
- @SmallTest
+ @Test
public void testGetImplicitlyApplicableSubtypesLocked() throws Exception {
final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US",
SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
@@ -434,8 +448,8 @@
InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(Locale.forLanguageTag("sr-Latn-RS")), imi);
assertEquals(2, result.size());
- assertThat(nonAutoSrLatn, isIn(result));
- assertThat(nonAutoHandwritingSrLatn, isIn(result));
+ assertThat(nonAutoSrLatn, is(in(result)));
+ assertThat(nonAutoHandwritingSrLatn, is(in(result)));
}
{
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
@@ -454,8 +468,8 @@
InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(Locale.forLanguageTag("sr-Cyrl-RS")), imi);
assertEquals(2, result.size());
- assertThat(nonAutoSrCyrl, isIn(result));
- assertThat(nonAutoHandwritingSrCyrl, isIn(result));
+ assertThat(nonAutoSrCyrl, is(in(result)));
+ assertThat(nonAutoHandwritingSrCyrl, is(in(result)));
}
// Make sure that secondary locales are taken into account to find the best matching
@@ -486,12 +500,12 @@
Locale.forLanguageTag("en-US")),
imi);
assertEquals(6, result.size());
- assertThat(nonAutoEnGB, isIn(result));
- assertThat(nonAutoFr, isIn(result));
- assertThat(nonAutoSrLatn, isIn(result));
- assertThat(nonAutoHandwritingEn, isIn(result));
- assertThat(nonAutoHandwritingFr, isIn(result));
- assertThat(nonAutoHandwritingSrLatn, isIn(result));
+ assertThat(nonAutoEnGB, is(in(result)));
+ assertThat(nonAutoFr, is(in(result)));
+ assertThat(nonAutoSrLatn, is(in(result)));
+ assertThat(nonAutoHandwritingEn, is(in(result)));
+ assertThat(nonAutoHandwritingFr, is(in(result)));
+ assertThat(nonAutoHandwritingSrLatn, is(in(result)));
}
// Make sure that 3-letter language code can be handled.
@@ -604,16 +618,16 @@
final ArrayList<InputMethodSubtype> result =
InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_FR, LOCALE_EN_US, LOCALE_JA_JP), imi);
- assertThat(nonAutoFrCA, isIn(result));
- assertThat(nonAutoEnUS, isIn(result));
- assertThat(nonAutoJa, isIn(result));
- assertThat(nonAutoIn, not(isIn(result)));
- assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(isIn(result)));
- assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(isIn(result)));
+ assertThat(nonAutoFrCA, is(in(result)));
+ assertThat(nonAutoEnUS, is(in(result)));
+ assertThat(nonAutoJa, is(in(result)));
+ assertThat(nonAutoIn, not(is(in(result))));
+ assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(is(in(result))));
+ assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(is(in(result))));
}
}
- @SmallTest
+ @Test
public void testContainsSubtypeOf() throws Exception {
final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US",
SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
@@ -788,7 +802,7 @@
private Context createTargetContextWithLocales(final LocaleList locales) {
final Configuration resourceConfiguration = new Configuration();
resourceConfiguration.setLocales(locales);
- return getInstrumentation()
+ return InstrumentationRegistry.getInstrumentation()
.getTargetContext()
.createConfigurationContext(resourceConfiguration);
}
@@ -1043,7 +1057,7 @@
return preinstalledImes;
}
- @SmallTest
+ @Test
public void testGetSuitableLocalesForSpellChecker() throws Exception {
{
final ArrayList<Locale> locales =
@@ -1138,7 +1152,7 @@
}
}
- @SmallTest
+ @Test
public void testParseInputMethodsAndSubtypesString() {
// Trivial cases.
{
@@ -1264,7 +1278,7 @@
}
}
- @SmallTest
+ @Test
public void testbuildInputMethodsAndSubtypesString() {
{
ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
@@ -1272,7 +1286,7 @@
}
{
ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
- map.put("ime0", new ArraySet<String>());
+ map.put("ime0", new ArraySet<>());
assertEquals("ime0", InputMethodUtils.buildInputMethodsAndSubtypesString(map));
}
{
@@ -1300,8 +1314,8 @@
}
{
ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
- map.put("ime0", new ArraySet<String>());
- map.put("ime1", new ArraySet<String>());
+ map.put("ime0", new ArraySet<>());
+ map.put("ime1", new ArraySet<>());
ArraySet<String> validSequences = new ArraySet<>();
validSequences.add("ime0:ime1");
@@ -1314,7 +1328,7 @@
ArraySet<String> subtypes1 = new ArraySet<>();
subtypes1.add("subtype0");
map.put("ime0", subtypes1);
- map.put("ime1", new ArraySet<String>());
+ map.put("ime1", new ArraySet<>());
ArraySet<String> validSequences = new ArraySet<>();
validSequences.add("ime0;subtype0:ime1");
@@ -1328,7 +1342,7 @@
subtypes1.add("subtype0");
subtypes1.add("subtype1");
map.put("ime0", subtypes1);
- map.put("ime1", new ArraySet<String>());
+ map.put("ime1", new ArraySet<>());
ArraySet<String> validSequences = new ArraySet<>();
validSequences.add("ime0;subtype0;subtype1:ime1");
@@ -1380,7 +1394,7 @@
}
}
- @SmallTest
+ @Test
public void testConstructLocaleFromString() throws Exception {
assertEquals(new Locale("en"), InputMethodUtils.constructLocaleFromString("en"));
assertEquals(new Locale("en", "US"), InputMethodUtils.constructLocaleFromString("en_US"));
@@ -1400,4 +1414,29 @@
assertEquals(new Locale("a b c"), InputMethodUtils.constructLocaleFromString("a b c"));
assertEquals(new Locale("en-US"), InputMethodUtils.constructLocaleFromString("en-US"));
}
+
+ @Test
+ public void testIsSoftInputModeStateVisibleAllowed() {
+ // On pre-P devices, SOFT_INPUT_STATE_VISIBLE/SOFT_INPUT_STATE_ALWAYS_VISIBLE are always
+ // allowed, regardless of the focused view state.
+ assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
+ Build.VERSION_CODES.O_MR1, 0));
+ assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
+ Build.VERSION_CODES.O_MR1, CONTROL_WINDOW_VIEW_HAS_FOCUS));
+ assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
+ Build.VERSION_CODES.O_MR1,
+ CONTROL_WINDOW_VIEW_HAS_FOCUS | CONTROL_WINDOW_IS_TEXT_EDITOR));
+
+ // On P+ devices, SOFT_INPUT_STATE_VISIBLE/SOFT_INPUT_STATE_ALWAYS_VISIBLE are allowed only
+ // when there is a focused View and its View#onCheckIsTextEditor() returns true.
+ assertFalse(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
+ Build.VERSION_CODES.P, 0));
+ assertFalse(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
+ Build.VERSION_CODES.P, CONTROL_WINDOW_VIEW_HAS_FOCUS));
+ assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
+ Build.VERSION_CODES.P,
+ CONTROL_WINDOW_VIEW_HAS_FOCUS | CONTROL_WINDOW_IS_TEXT_EDITOR));
+
+ }
+
}
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
index cd339fb..549511a 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
@@ -16,24 +16,25 @@
package com.android.internal.inputmethod;
+import static org.junit.Assert.assertEquals;
+
import android.os.LocaleList;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.Locale;
-public class LocaleUtilsTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LocaleUtilsTest {
- private static final LocaleUtils.LocaleExtractor<Locale> sIdentityMapper =
- new LocaleUtils.LocaleExtractor<Locale>() {
- @Override
- public Locale get(Locale source) {
- return source;
- }
- };
+ private static final LocaleUtils.LocaleExtractor<Locale> sIdentityMapper = source -> source;
- @SmallTest
+ @Test
public void testFilterByLanguageEmptyLanguageList() throws Exception {
final ArrayList<Locale> availableLocales = new ArrayList<>();
availableLocales.add(Locale.forLanguageTag("en-US"));
@@ -49,7 +50,7 @@
assertEquals(0, dest.size());
}
- @SmallTest
+ @Test
public void testFilterDoesNotMatchAnything() throws Exception {
final ArrayList<Locale> availableLocales = new ArrayList<>();
availableLocales.add(Locale.forLanguageTag("en-US"));
@@ -65,7 +66,7 @@
assertEquals(0, dest.size());
}
- @SmallTest
+ @Test
public void testFilterByLanguageEmptySource() throws Exception {
final ArrayList<Locale> availableLocales = new ArrayList<>();
@@ -76,7 +77,7 @@
assertEquals(0, dest.size());
}
- @SmallTest
+ @Test
public void testFilterByLanguageNullAvailableLocales() throws Exception {
{
final LocaleList preferredLocales =
@@ -138,7 +139,7 @@
}
}
- @SmallTest
+ @Test
public void testFilterByLanguage() throws Exception {
{
final ArrayList<Locale> availableLocales = new ArrayList<>();
@@ -172,7 +173,7 @@
}
}
- @SmallTest
+ @Test
public void testFilterByLanguageTheSameLanguage() throws Exception {
{
final LocaleList preferredLocales =
@@ -223,7 +224,7 @@
}
}
- @SmallTest
+ @Test
public void testFilterByLanguageFallbackRules() throws Exception {
{
final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-Latn-RS");
@@ -355,6 +356,7 @@
}
}
+ @Test
public void testFilterKnownLimitation() throws Exception {
// Following test cases are not for intentional behavior but checks for preventing the
// behavior from becoming worse.
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index 682a002..4b197e4 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -104,7 +104,9 @@
@Test
public void testCpuFreqTimes() throws Exception {
- assumeTrue(sCpuFreqTimesAvailable);
+ if (!sCpuFreqTimesAvailable) {
+ return;
+ }
batteryOnScreenOn();
forceStop();
@@ -126,7 +128,9 @@
@Test
public void testCpuFreqTimes_screenOff() throws Exception {
- assumeTrue(sCpuFreqTimesAvailable);
+ if (!sCpuFreqTimesAvailable) {
+ return;
+ }
batteryOnScreenOff();
forceStop();
@@ -154,7 +158,9 @@
@Test
public void testCpuFreqTimes_isolatedProcess() throws Exception {
- assumeTrue(sCpuFreqTimesAvailable);
+ if (!sCpuFreqTimesAvailable) {
+ return;
+ }
batteryOnScreenOn();
forceStop();
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/hosttests/test-apps/DownloadManagerTestApp/Android.mk b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
index 47ee2cf..1d9f624 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
@@ -20,8 +20,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := android-common mockwebserver junit legacy-android-test
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := android-common mockwebserver junit
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_PACKAGE_NAME := DownloadManagerTestApp
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk
index b35cbae..193e601 100644
--- a/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk
+++ b/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk
@@ -20,7 +20,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test junit
+LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_SDK_VERSION := current
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk
index 06812b5..9f44767 100644
--- a/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk
@@ -20,7 +20,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test junit
+LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_SDK_VERSION := current
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk
index 48bceaf..b4d354c 100644
--- a/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk
@@ -20,7 +20,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test junit
+LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_SDK_VERSION := current
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk
index 569d102..969e588 100644
--- a/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk
@@ -20,7 +20,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test junit
+LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_SDK_VERSION := current
diff --git a/core/tests/notificationtests/Android.mk b/core/tests/notificationtests/Android.mk
index 0551eb6..30c2dca 100644
--- a/core/tests/notificationtests/Android.mk
+++ b/core/tests/notificationtests/Android.mk
@@ -8,12 +8,11 @@
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 := NotificationStressTests
LOCAL_STATIC_JAVA_LIBRARIES := \
junit \
- legacy-android-test \
ub-uiautomator
include $(BUILD_PACKAGE)
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/RippleComponent.java b/graphics/java/android/graphics/drawable/RippleComponent.java
index 0e38826..626bcee 100644
--- a/graphics/java/android/graphics/drawable/RippleComponent.java
+++ b/graphics/java/android/graphics/drawable/RippleComponent.java
@@ -93,12 +93,8 @@
protected final void onHotspotBoundsChanged() {
if (!mHasMaxRadius) {
- final float halfWidth = mBounds.width() / 2.0f;
- final float halfHeight = mBounds.height() / 2.0f;
- final float targetRadius = (float) Math.sqrt(halfWidth * halfWidth
- + halfHeight * halfHeight);
-
- onTargetRadiusChanged(targetRadius);
+ mTargetRadius = getTargetRadius(mBounds);
+ onTargetRadiusChanged(mTargetRadius);
}
}
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 8b185f2..734cff5 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -299,6 +299,12 @@
onHotspotBoundsChanged();
}
+ final int count = mExitingRipplesCount;
+ final RippleForeground[] ripples = mExitingRipples;
+ for (int i = 0; i < count; i++) {
+ ripples[i].onBoundsChange();
+ }
+
if (mBackground != null) {
mBackground.onBoundsChange();
}
@@ -560,8 +566,7 @@
y = mHotspotBounds.exactCenterY();
}
- final boolean isBounded = isBounded();
- mRipple = new RippleForeground(this, mHotspotBounds, x, y, isBounded, mForceSoftware);
+ mRipple = new RippleForeground(this, mHotspotBounds, x, y, mForceSoftware);
}
mRipple.setup(mState.mMaxRadius, mDensity);
diff --git a/graphics/java/android/graphics/drawable/RippleForeground.java b/graphics/java/android/graphics/drawable/RippleForeground.java
index 0b5020c..ecbf578 100644
--- a/graphics/java/android/graphics/drawable/RippleForeground.java
+++ b/graphics/java/android/graphics/drawable/RippleForeground.java
@@ -30,6 +30,7 @@
import android.view.RenderNodeAnimator;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
+import android.view.animation.PathInterpolator;
import java.util.ArrayList;
@@ -38,18 +39,14 @@
*/
class RippleForeground extends RippleComponent {
private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
- private static final TimeInterpolator DECELERATE_INTERPOLATOR = new LogDecelerateInterpolator(
- 400f, 1.4f, 0);
+ // Matches R.interpolator.fast_out_slow_in but as we have no context we can't just import that
+ private static final TimeInterpolator DECELERATE_INTERPOLATOR =
+ new PathInterpolator(0.4f, 0f, 0.2f, 1f);
- // Pixel-based accelerations and velocities.
- private static final float WAVE_TOUCH_DOWN_ACCELERATION = 2048;
- private static final float WAVE_OPACITY_DECAY_VELOCITY = 3;
-
- // Bounded ripple animation properties.
- private static final int BOUNDED_ORIGIN_EXIT_DURATION = 300;
- private static final int BOUNDED_RADIUS_EXIT_DURATION = 800;
- private static final int BOUNDED_OPACITY_EXIT_DURATION = 400;
- private static final float MAX_BOUNDED_RADIUS = 350;
+ // Time it takes for the ripple to expand
+ private static final int RIPPLE_ENTER_DURATION = 225;
+ // Time it takes for the ripple to slide from the touch to the center point
+ private static final int RIPPLE_ORIGIN_DURATION = 225;
private static final int OPACITY_ENTER_DURATION = 75;
private static final int OPACITY_EXIT_DURATION = 150;
@@ -71,9 +68,6 @@
private float mTargetX = 0;
private float mTargetY = 0;
- /** Ripple target radius used when bounded. Not used for clamping. */
- private float mBoundedRadius = 0;
-
// Software rendering properties.
private float mOpacity = 0;
@@ -107,19 +101,13 @@
private float mStartRadius = 0;
public RippleForeground(RippleDrawable owner, Rect bounds, float startingX, float startingY,
- boolean isBounded, boolean forceSoftware) {
+ boolean forceSoftware) {
super(owner, bounds);
mForceSoftware = forceSoftware;
mStartingX = startingX;
mStartingY = startingY;
- if (isBounded) {
- mBoundedRadius = MAX_BOUNDED_RADIUS * 0.9f
- + (float) (MAX_BOUNDED_RADIUS * Math.random() * 0.1);
- } else {
- mBoundedRadius = 0;
- }
// Take 60% of the maximum of the width and height, then divided half to get the radius.
mStartRadius = Math.max(bounds.width(), bounds.height()) * 0.3f;
}
@@ -127,6 +115,7 @@
@Override
protected void onTargetRadiusChanged(float targetRadius) {
clampStartingPosition();
+ switchToUiThreadAnimation();
}
private void drawSoftware(Canvas c, Paint p) {
@@ -228,16 +217,14 @@
}
mRunningSwAnimators.clear();
- final int duration = getRadiusDuration();
-
final ObjectAnimator tweenRadius = ObjectAnimator.ofFloat(this, TWEEN_RADIUS, 1);
- tweenRadius.setDuration(duration);
+ tweenRadius.setDuration(RIPPLE_ENTER_DURATION);
tweenRadius.setInterpolator(DECELERATE_INTERPOLATOR);
tweenRadius.start();
mRunningSwAnimators.add(tweenRadius);
final ObjectAnimator tweenOrigin = ObjectAnimator.ofFloat(this, TWEEN_ORIGIN, 1);
- tweenOrigin.setDuration(duration);
+ tweenOrigin.setDuration(RIPPLE_ORIGIN_DURATION);
tweenOrigin.setInterpolator(DECELERATE_INTERPOLATOR);
tweenOrigin.start();
mRunningSwAnimators.add(tweenOrigin);
@@ -267,20 +254,18 @@
final Paint paint = mOwner.getRipplePaint();
mPropPaint = CanvasProperty.createPaint(paint);
- final int radiusDuration = getRadiusDuration();
-
final RenderNodeAnimator radius = new RenderNodeAnimator(mPropRadius, mTargetRadius);
- radius.setDuration(radiusDuration);
+ radius.setDuration(RIPPLE_ORIGIN_DURATION);
radius.setInterpolator(DECELERATE_INTERPOLATOR);
mPendingHwAnimators.add(radius);
final RenderNodeAnimator x = new RenderNodeAnimator(mPropX, mTargetX);
- x.setDuration(radiusDuration);
+ x.setDuration(RIPPLE_ORIGIN_DURATION);
x.setInterpolator(DECELERATE_INTERPOLATOR);
mPendingHwAnimators.add(x);
final RenderNodeAnimator y = new RenderNodeAnimator(mPropY, mTargetY);
- y.setDuration(radiusDuration);
+ y.setDuration(RIPPLE_ORIGIN_DURATION);
y.setInterpolator(DECELERATE_INTERPOLATOR);
mPendingHwAnimators.add(y);
@@ -333,12 +318,6 @@
return MathUtils.lerp(mClampedStartingY - mBounds.exactCenterY(), mTargetY, mTweenY);
}
- private int getRadiusDuration() {
- final float remainingRadius = mTargetRadius - getCurrentRadius();
- return (int) (1000 * Math.sqrt(remainingRadius / WAVE_TOUCH_DOWN_ACCELERATION *
- mDensityScale) + 0.5);
- }
-
private float getCurrentRadius() {
return MathUtils.lerp(mStartRadius, mTargetRadius, mTweenRadius);
}
@@ -402,6 +381,14 @@
}
}
+ private void clearHwProps() {
+ mPropPaint = null;
+ mPropRadius = null;
+ mPropX = null;
+ mPropY = null;
+ mUsingProperties = false;
+ }
+
private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
@@ -410,39 +397,20 @@
pruneSwFinished();
if (mRunningHwAnimators.isEmpty()) {
- mPropPaint = null;
- mPropRadius = null;
- mPropX = null;
- mPropY = null;
+ clearHwProps();
}
}
};
- /**
- * Interpolator with a smooth log deceleration.
- */
- private static final class LogDecelerateInterpolator implements TimeInterpolator {
- private final float mBase;
- private final float mDrift;
- private final float mTimeScale;
- private final float mOutputScale;
-
- public LogDecelerateInterpolator(float base, float timeScale, float drift) {
- mBase = base;
- mDrift = drift;
- mTimeScale = 1f / timeScale;
-
- mOutputScale = 1f / computeLog(1f);
+ private void switchToUiThreadAnimation() {
+ for (int i = 0; i < mRunningHwAnimators.size(); i++) {
+ Animator animator = mRunningHwAnimators.get(i);
+ animator.removeListener(mAnimationListener);
+ animator.end();
}
-
- private float computeLog(float t) {
- return 1f - (float) Math.pow(mBase, -t * mTimeScale) + (mDrift * t);
- }
-
- @Override
- public float getInterpolation(float t) {
- return computeLog(t) * mOutputScale;
- }
+ mRunningHwAnimators.clear();
+ clearHwProps();
+ invalidateSelf();
}
/**
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/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/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index d6b1cf1..a250d1f0 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -39,13 +39,12 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- value = {
- PURPOSE_ENCRYPT,
- PURPOSE_DECRYPT,
- PURPOSE_SIGN,
- PURPOSE_VERIFY,
- })
+ @IntDef(flag = true, prefix = { "PURPOSE_" }, value = {
+ PURPOSE_ENCRYPT,
+ PURPOSE_DECRYPT,
+ PURPOSE_SIGN,
+ PURPOSE_VERIFY,
+ })
public @interface PurposeEnum {}
/**
@@ -126,7 +125,7 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @StringDef({
+ @StringDef(prefix = { "KEY_" }, value = {
KEY_ALGORITHM_RSA,
KEY_ALGORITHM_EC,
KEY_ALGORITHM_AES,
@@ -267,7 +266,7 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @StringDef({
+ @StringDef(prefix = { "BLOCK_MODE_" }, value = {
BLOCK_MODE_ECB,
BLOCK_MODE_CBC,
BLOCK_MODE_CTR,
@@ -354,7 +353,7 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @StringDef({
+ @StringDef(prefix = { "ENCRYPTION_PADDING_" }, value = {
ENCRYPTION_PADDING_NONE,
ENCRYPTION_PADDING_PKCS7,
ENCRYPTION_PADDING_RSA_PKCS1,
@@ -437,7 +436,7 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @StringDef({
+ @StringDef(prefix = { "SIGNATURE_PADDING_" }, value = {
SIGNATURE_PADDING_RSA_PKCS1,
SIGNATURE_PADDING_RSA_PSS,
})
@@ -497,7 +496,7 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @StringDef({
+ @StringDef(prefix = { "DIGEST_" }, value = {
DIGEST_NONE,
DIGEST_MD5,
DIGEST_SHA1,
@@ -647,11 +646,12 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
- ORIGIN_GENERATED,
- ORIGIN_IMPORTED,
- ORIGIN_UNKNOWN,
- })
+ @IntDef(prefix = { "ORIGIN_" }, value = {
+ ORIGIN_GENERATED,
+ ORIGIN_IMPORTED,
+ ORIGIN_UNKNOWN,
+ })
+
public @interface OriginEnum {}
/** Key was generated inside AndroidKeyStore. */
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.aidl
similarity index 75%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.aidl
index 353728a..3fb7b4f 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.aidl
@@ -14,12 +14,6 @@
* limitations under the License.
*/
-package com.android.server.timezone;
+package android.security.keystore;
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
-
- long currentTimestamp();
-}
+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..7cb8e37
--- /dev/null
+++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
@@ -0,0 +1,185 @@
+/*
+ * 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());
+ out.writeLong(mSpec.getCertificateNotBefore().getTime());
+ out.writeLong(mSpec.getCertificateNotAfter().getTime());
+ writeOptionalDate(out, mSpec.getKeyValidityStart());
+ writeOptionalDate(out, mSpec.getKeyValidityForOriginationEnd());
+ writeOptionalDate(out, mSpec.getKeyValidityForConsumptionEnd());
+ if (mSpec.isDigestsSpecified()) {
+ out.writeStringArray(mSpec.getDigests());
+ } else {
+ out.writeStringArray(null);
+ }
+ 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());
+ // KeySize is -1 by default, if the KeyGenParameterSpec previously parcelled had the default
+ // value, do not set it as this will cause setKeySize to throw.
+ int keySize = in.readInt();
+ if (keySize >= 0) {
+ builder.setKeySize(keySize);
+ }
+
+ 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", keySpecType));
+ }
+ if (algorithmSpec != null) {
+ builder.setAlgorithmParameterSpec(algorithmSpec);
+ }
+ builder.setCertificateSubject(new X500Principal(in.createByteArray()));
+ builder.setCertificateSerialNumber(new BigInteger(in.createByteArray()));
+ builder.setCertificateNotBefore(new Date(in.readLong()));
+ builder.setCertificateNotAfter(new Date(in.readLong()));
+ builder.setKeyValidityStart(readDateOrNull(in));
+ builder.setKeyValidityForOriginationEnd(readDateOrNull(in));
+ builder.setKeyValidityForConsumptionEnd(readDateOrNull(in));
+ String[] digests = in.createStringArray();
+ if (digests != null) {
+ builder.setDigests(digests);
+ }
+ 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..1167f76
--- /dev/null
+++ b/keystore/tests/Android.mk
@@ -0,0 +1,33 @@
+# 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
+
+LOCAL_PACKAGE_NAME := KeystoreTests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
diff --git a/tests/CantSaveState2/AndroidManifest.xml b/keystore/tests/AndroidManifest.xml
similarity index 61%
rename from tests/CantSaveState2/AndroidManifest.xml
rename to keystore/tests/AndroidManifest.xml
index 8f4f01d..9bf2d0c 100644
--- a/tests/CantSaveState2/AndroidManifest.xml
+++ b/keystore/tests/AndroidManifest.xml
@@ -14,14 +14,15 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.cantsavestate2">
- <application android:label="Can't Save 2" android:cantSaveState="true">
- <activity android:name="CantSave2Activity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
+ 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/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/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 ba5844b..6c43a67 100644
--- a/libs/androidfw/tests/ApkAssets_test.cpp
+++ b/libs/androidfw/tests/ApkAssets_test.cpp
@@ -39,7 +39,6 @@
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);
@@ -59,7 +58,6 @@
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);
@@ -114,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");
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..7cacaf6 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -122,7 +122,7 @@
instrumentation: true,
profile_file: "hwui/hwui.profdata",
benchmarks: ["hwui"],
- enable_profile_use: false,
+ enable_profile_use: true,
},
}
@@ -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/NinePatchUtils.h b/libs/hwui/NinePatchUtils.h
index 8f866f5..db9509f 100644
--- a/libs/hwui/NinePatchUtils.h
+++ b/libs/hwui/NinePatchUtils.h
@@ -53,10 +53,13 @@
return xRects * yRects;
}
-static inline void SetLatticeFlags(SkCanvas::Lattice* lattice, SkCanvas::Lattice::Flags* flags,
- int numFlags, const Res_png_9patch& chunk) {
- lattice->fFlags = flags;
- sk_bzero(flags, numFlags * sizeof(SkCanvas::Lattice::Flags));
+static inline void SetLatticeFlags(SkCanvas::Lattice* lattice,
+ SkCanvas::Lattice::RectType* flags, int numFlags, const Res_png_9patch& chunk,
+ SkColor* colors) {
+ lattice->fRectTypes = flags;
+ lattice->fColors = colors;
+ sk_bzero(flags, numFlags * sizeof(SkCanvas::Lattice::RectType));
+ sk_bzero(colors, numFlags * sizeof(SkColor));
bool needPadRow = lattice->fYCount > 0 && 0 == lattice->fYDivs[0];
bool needPadCol = lattice->fXCount > 0 && 0 == lattice->fXDivs[0];
@@ -65,6 +68,7 @@
if (needPadRow) {
// Skip flags for the degenerate first row of rects.
flags += lattice->fXCount + 1;
+ colors += lattice->fXCount + 1;
yCount--;
}
@@ -75,20 +79,28 @@
if (0 == x && needPadCol) {
// First rect of each column is degenerate, skip the flag.
flags++;
+ colors++;
continue;
}
- if (0 == chunk.getColors()[i++]) {
- *flags = SkCanvas::Lattice::kTransparent_Flags;
+ uint32_t currentColor = chunk.getColors()[i++];
+ if (Res_png_9patch::TRANSPARENT_COLOR == currentColor) {
+ *flags = SkCanvas::Lattice::kTransparent;
+ setFlags = true;
+ } else if (Res_png_9patch::NO_COLOR != currentColor) {
+ *flags = SkCanvas::Lattice::kFixedColor;
+ *colors = currentColor;
setFlags = true;
}
flags++;
+ colors++;
}
}
if (!setFlags) {
- lattice->fFlags = nullptr;
+ lattice->fRectTypes = nullptr;
+ lattice->fColors = nullptr;
}
}
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index 77d7bef..4ddacc8 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -42,8 +42,15 @@
mBounds.set(left, top, right, bottom);
mRadius = radius;
+
+ // Reuse memory if previous outline was the same shape (rect or round rect).
+ if ( mPath.countVerbs() > 10) {
+ mPath.reset();
+ } else {
+ mPath.rewind();
+ }
+
// update mPath to reflect new outline
- mPath.reset();
if (MathUtils::isPositive(radius)) {
mPath.addRoundRect(SkRect::MakeLTRB(left, top, right, bottom), radius, radius);
} else {
diff --git a/libs/hwui/ProfileDataContainer.cpp b/libs/hwui/ProfileDataContainer.cpp
index 8e0b4e2..38e0f0a 100644
--- a/libs/hwui/ProfileDataContainer.cpp
+++ b/libs/hwui/ProfileDataContainer.cpp
@@ -21,6 +21,7 @@
#include <cutils/ashmem.h>
#include <log/log.h>
+#include <errno.h>
#include <sys/mman.h>
namespace android {
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..13e1ebe 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -699,7 +699,8 @@
SkCanvas::Lattice lattice;
NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
- lattice.fFlags = nullptr;
+ lattice.fRectTypes = nullptr;
+ lattice.fColors = nullptr;
int numFlags = 0;
if (chunk.numColors > 0 && chunk.numColors == NinePatchUtils::NumDistinctRects(lattice)) {
// We can expect the framework to give us a color for every distinct rect.
@@ -707,9 +708,10 @@
numFlags = (lattice.fXCount + 1) * (lattice.fYCount + 1);
}
- SkAutoSTMalloc<25, SkCanvas::Lattice::Flags> flags(numFlags);
+ SkAutoSTMalloc<25, SkCanvas::Lattice::RectType> flags(numFlags);
+ SkAutoSTMalloc<25, SkColor> colors(numFlags);
if (numFlags > 0) {
- NinePatchUtils::SetLatticeFlags(&lattice, flags.get(), numFlags, chunk);
+ NinePatchUtils::SetLatticeFlags(&lattice, flags.get(), numFlags, chunk, colors.get());
}
lattice.fBounds = nullptr;
@@ -738,6 +740,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/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index 288d039..107890e 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -45,8 +45,7 @@
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
LOG_ALWAYS_FATAL_IF(!glInterface.get());
- grContext.reset(GrContext::Create(GrBackend::kOpenGL_GrBackend,
- (GrBackendContext)glInterface.get()));
+ grContext = GrContext::MakeGL(std::move(glInterface));
} else {
grContext->resetContext();
}
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index d5fe7f4..9db39d9 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -22,8 +22,6 @@
#include <SkOverdrawColorFilter.h>
#include <SkPicture.h>
#include <SkPictureRecorder.h>
-#include <SkPixelSerializer.h>
-#include <SkStream.h>
#include "VectorDrawable.h"
#include "utils/TraceUtils.h"
@@ -161,14 +159,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);
@@ -203,19 +205,6 @@
}
}
-// Encodes to PNG, unless there is already encoded data, in which case that gets
-// used.
-class PngPixelSerializer : public SkPixelSerializer {
-public:
- bool onUseEncodedData(const void*, size_t) override { return true; }
- SkData* onEncode(const SkPixmap& pixmap) override {
- SkDynamicMemoryWStream buf;
- return SkEncodeImage(&buf, pixmap, SkEncodedImageFormat::kPNG, 100)
- ? buf.detachAsData().release()
- : nullptr;
- }
-};
-
void SkiaPipeline::renderVectorDrawableCache() {
if (!mVectorDrawables.empty()) {
sp<VectorDrawableAtlas> atlas = mRenderThread.cacheManager().acquireVectorDrawableAtlas();
@@ -292,9 +281,7 @@
sk_sp<SkPicture> picture = mRecorder->finishRecordingAsPicture();
surface->getCanvas()->drawPicture(picture);
if (picture->approximateOpCount() > 0) {
- SkDynamicMemoryWStream stream;
- PngPixelSerializer serializer;
- picture->serialize(&stream, &serializer);
+ auto data = picture->serialize();
// offload saving to file in a different thread
if (!mSavePictureProcessor.get()) {
@@ -303,10 +290,10 @@
taskManager->canRunTasks() ? taskManager : nullptr);
}
if (1 == mCaptureSequence) {
- mSavePictureProcessor->savePicture(stream.detachAsData(), mCapturedFile);
+ mSavePictureProcessor->savePicture(data, mCapturedFile);
} else {
mSavePictureProcessor->savePicture(
- stream.detachAsData(),
+ data,
mCapturedFile + "_" + std::to_string(mCaptureSequence));
}
mCaptureSequence--;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 91b35c2..035cea3 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -218,7 +218,8 @@
SkCanvas::Lattice lattice;
NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
- lattice.fFlags = nullptr;
+ lattice.fRectTypes = nullptr;
+ lattice.fColors = nullptr;
int numFlags = 0;
if (chunk.numColors > 0 && chunk.numColors == NinePatchUtils::NumDistinctRects(lattice)) {
// We can expect the framework to give us a color for every distinct rect.
@@ -226,9 +227,10 @@
numFlags = (lattice.fXCount + 1) * (lattice.fYCount + 1);
}
- SkAutoSTMalloc<25, SkCanvas::Lattice::Flags> flags(numFlags);
+ SkAutoSTMalloc<25, SkCanvas::Lattice::RectType> flags(numFlags);
+ SkAutoSTMalloc<25, SkColor> colors(numFlags);
if (numFlags > 0) {
- NinePatchUtils::SetLatticeFlags(&lattice, flags.get(), numFlags, chunk);
+ NinePatchUtils::SetLatticeFlags(&lattice, flags.get(), numFlags, chunk, colors.get());
}
lattice.fBounds = nullptr;
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index a33b287..907f2d2 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,15 +48,18 @@
mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(
mMaxSurfaceArea / 2,
skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface);
+ if (Properties::isSkiaEnabled()) {
+ skiapipeline::ShaderCache::get().initShaderDiskCache();
+ }
}
-void CacheManager::reset(GrContext* context) {
- if (context != mGrContext.get()) {
+void CacheManager::reset(sk_sp<GrContext> context) {
+ if (context != mGrContext) {
destroy();
}
if (context) {
- mGrContext = sk_ref_sp(context);
+ mGrContext = std::move(context);
mGrContext->getResourceCacheLimits(&mMaxResources, nullptr);
updateContextCacheSizes();
}
@@ -127,6 +132,8 @@
}
contextOptions->fExecutor = mTaskProcessor.get();
}
+
+ contextOptions->fPersistentCache = &skiapipeline::ShaderCache::get();
}
void CacheManager::trimMemory(TrimMemoryMode mode) {
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
index d037045..7d73352 100644
--- a/libs/hwui/renderthread/CacheManager.h
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -61,7 +61,7 @@
CacheManager(const DisplayInfo& display);
- void reset(GrContext* grContext);
+ void reset(sk_sp<GrContext> grContext);
void destroy();
void updateContextCacheSizes();
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/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 4df7caf..5b87e10 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -141,8 +141,9 @@
GrContextOptions options;
options.fDisableDistanceFieldPaths = true;
mRenderThread.cacheManager().configureContext(&options);
- mRenderThread.setGrContext(GrContext::Create(GrBackend::kOpenGL_GrBackend,
- (GrBackendContext)glInterface.get(), options));
+ sk_sp<GrContext> grContext(GrContext::MakeGL(std::move(glInterface), options));
+ LOG_ALWAYS_FATAL_IF(!grContext.get());
+ mRenderThread.setGrContext(grContext);
}
}
@@ -238,9 +239,9 @@
if (!eglChooseConfig(mEglDisplay, attribs16F, &mEglConfigWideGamut, numConfigs,
&numConfigs) ||
numConfigs != 1) {
- LOG_ALWAYS_FATAL(
- "Device claims wide gamut support, cannot find matching config, error = %s",
+ ALOGE("Device claims wide gamut support, cannot find matching config, error = %s",
eglErrorString());
+ EglExtensions.pixelFormatFloat = false;
}
}
}
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 05a9b75..79dc09f 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
@@ -166,12 +173,12 @@
return *mReadback;
}
-void RenderThread::setGrContext(GrContext* context) {
+void RenderThread::setGrContext(sk_sp<GrContext> context) {
mCacheManager->reset(context);
- if (mGrContext.get()) {
+ if (mGrContext) {
mGrContext->releaseResourcesAndAbandonContext();
}
- mGrContext.reset(context);
+ mGrContext = std::move(context);
}
int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
@@ -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..3aa5487 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
@@ -85,7 +88,7 @@
const DisplayInfo& mainDisplayInfo() { return mDisplayInfo; }
GrContext* getGrContext() const { return mGrContext.get(); }
- void setGrContext(GrContext* cxt);
+ void setGrContext(sk_sp<GrContext> cxt);
CacheManager& cacheManager() { return *mCacheManager; }
VulkanManager& vulkanManager() { return *mVkManager; }
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index a693e68..9d246ff 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -58,6 +58,7 @@
mBackendContext.reset(GrVkBackendContext::Create(vkGetInstanceProcAddr, vkGetDeviceProcAddr,
&mPresentQueueIndex, canPresent));
+ LOG_ALWAYS_FATAL_IF(!mBackendContext.get());
// Get all the addresses of needed vulkan functions
VkInstance instance = mBackendContext->fInstance;
@@ -110,8 +111,9 @@
GrContextOptions options;
options.fDisableDistanceFieldPaths = true;
mRenderThread.cacheManager().configureContext(&options);
- mRenderThread.setGrContext(
- GrContext::Create(kVulkan_GrBackend, (GrBackendContext)mBackendContext.get(), options));
+ sk_sp<GrContext> grContext(GrContext::MakeVulkan(mBackendContext, options));
+ LOG_ALWAYS_FATAL_IF(!grContext.get());
+ mRenderThread.setGrContext(grContext);
DeviceInfo::initialize(mRenderThread.getGrContext()->caps()->maxRenderTargetSize());
if (Properties::enablePartialUpdates && Properties::useBufferAge) {
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index 3ac1a45..e0303a8 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -42,7 +42,7 @@
constexpr int sHistogramSize = ProfileData::HistogramSize();
static bool mergeProfileDataIntoProto(service::GraphicsStatsProto* proto,
- const std::string& package, int versionCode,
+ const std::string& package, int64_t versionCode,
int64_t startTime, int64_t endTime, const ProfileData* data);
static void dumpAsTextToFd(service::GraphicsStatsProto* proto, int outFd);
@@ -154,7 +154,7 @@
}
bool mergeProfileDataIntoProto(service::GraphicsStatsProto* proto, const std::string& package,
- int versionCode, int64_t startTime, int64_t endTime,
+ int64_t versionCode, int64_t startTime, int64_t endTime,
const ProfileData* data) {
if (proto->stats_start() == 0 || proto->stats_start() > startTime) {
proto->set_stats_start(startTime);
@@ -230,7 +230,7 @@
return;
}
dprintf(fd, "\nPackage: %s", proto->package_name().c_str());
- dprintf(fd, "\nVersion: %d", proto->version_code());
+ dprintf(fd, "\nVersion: %lld", proto->version_code());
dprintf(fd, "\nStats since: %lldns", proto->stats_start());
dprintf(fd, "\nStats end: %lldns", proto->stats_end());
auto summary = proto->summary();
@@ -254,7 +254,7 @@
}
void GraphicsStatsService::saveBuffer(const std::string& path, const std::string& package,
- int versionCode, int64_t startTime, int64_t endTime,
+ int64_t versionCode, int64_t startTime, int64_t endTime,
const ProfileData* data) {
service::GraphicsStatsProto statsProto;
if (!parseFromFile(path, &statsProto)) {
@@ -320,8 +320,8 @@
}
void GraphicsStatsService::addToDump(Dump* dump, const std::string& path,
- const std::string& package, int versionCode, int64_t startTime,
- int64_t endTime, const ProfileData* data) {
+ const std::string& package, int64_t versionCode,
+ int64_t startTime, int64_t endTime, const ProfileData* data) {
service::GraphicsStatsProto statsProto;
if (!path.empty() && !parseFromFile(path, &statsProto)) {
statsProto.Clear();
diff --git a/libs/hwui/service/GraphicsStatsService.h b/libs/hwui/service/GraphicsStatsService.h
index 7ddc219..bce0f3d 100644
--- a/libs/hwui/service/GraphicsStatsService.h
+++ b/libs/hwui/service/GraphicsStatsService.h
@@ -44,12 +44,12 @@
};
ANDROID_API static void saveBuffer(const std::string& path, const std::string& package,
- int versionCode, int64_t startTime, int64_t endTime,
+ int64_t versionCode, int64_t startTime, int64_t endTime,
const ProfileData* data);
ANDROID_API static Dump* createDump(int outFd, DumpType type);
ANDROID_API static void addToDump(Dump* dump, const std::string& path,
- const std::string& package, int versionCode,
+ const std::string& package, int64_t versionCode,
int64_t startTime, int64_t endTime, const ProfileData* data);
ANDROID_API static void addToDump(Dump* dump, const std::string& path);
ANDROID_API static void finishDump(Dump* dump);
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/Android.mk b/libs/incident/Android.mk
index 439e86d..8aa4b10 100644
--- a/libs/incident/Android.mk
+++ b/libs/incident/Android.mk
@@ -36,6 +36,7 @@
src/IncidentReportArgs.cpp
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_PROTO_OPTIMIZE_TYPE := lite
include $(BUILD_SHARED_LIBRARY)
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/GnssMeasurementsEvent.java b/location/java/android/location/GnssMeasurementsEvent.java
index d66fd9c..072a7fe 100644
--- a/location/java/android/location/GnssMeasurementsEvent.java
+++ b/location/java/android/location/GnssMeasurementsEvent.java
@@ -49,7 +49,7 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_LOCATION_DISABLED})
+ @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_LOCATION_DISABLED, STATUS_NOT_ALLOWED})
public @interface GnssMeasurementsStatus {}
/**
@@ -72,6 +72,12 @@
public static final int STATUS_LOCATION_DISABLED = 2;
/**
+ * The client is not allowed to register for GNSS Measurements in general or in the
+ * requested mode.
+ */
+ public static final int STATUS_NOT_ALLOWED = 3;
+
+ /**
* Reports the latest collected GNSS Measurements.
*/
public void onGnssMeasurementsReceived(GnssMeasurementsEvent eventArgs) {}
diff --git a/location/java/android/location/LocalListenerHelper.java b/location/java/android/location/LocalListenerHelper.java
index d7d2c513..592d01d 100644
--- a/location/java/android/location/LocalListenerHelper.java
+++ b/location/java/android/location/LocalListenerHelper.java
@@ -16,14 +16,14 @@
package android.location;
-import com.android.internal.util.Preconditions;
-
import android.annotation.NonNull;
import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.util.Preconditions;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -46,6 +46,11 @@
mTag = name;
}
+ /**
+ * Adds a {@param listener} to the list of listeners on which callbacks will be executed. The
+ * execution will happen on the {@param handler} thread or alternatively in the callback thread
+ * if a {@code null} handler value is passed.
+ */
public boolean add(@NonNull TListener listener, Handler handler) {
Preconditions.checkNotNull(listener);
synchronized (mListeners) {
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/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 65e7ced..6abba95 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -143,7 +143,7 @@
private int mQuality = POWER_LOW;
private long mInterval = 60 * 60 * 1000; // 60 minutes
- private long mFastestInterval = (long)(mInterval / FASTEST_INTERVAL_FACTOR); // 10 minutes
+ private long mFastestInterval = (long) (mInterval / FASTEST_INTERVAL_FACTOR); // 10 minutes
private boolean mExplicitFastestInterval = false;
private long mExpireAt = Long.MAX_VALUE; // no expiry
private int mNumUpdates = Integer.MAX_VALUE; // no expiry
@@ -151,7 +151,11 @@
private WorkSource mWorkSource = null;
private boolean mHideFromAppOps = false; // True if this request shouldn't be counted by AppOps
- private String mProvider = LocationManager.FUSED_PROVIDER; // for deprecated APIs that explicitly request a provider
+ private String mProvider = LocationManager.FUSED_PROVIDER;
+ // for deprecated APIs that explicitly request a provider
+
+ /** If true, GNSS chipset will make strong tradeoffs to substantially restrict power use */
+ private boolean mLowPowerMode = false;
/**
* Create a location request with default parameters.
@@ -184,11 +188,11 @@
}
LocationRequest request = new LocationRequest()
- .setProvider(provider)
- .setQuality(quality)
- .setInterval(minTime)
- .setFastestInterval(minTime)
- .setSmallestDisplacement(minDistance);
+ .setProvider(provider)
+ .setQuality(quality)
+ .setInterval(minTime)
+ .setFastestInterval(minTime)
+ .setSmallestDisplacement(minDistance);
if (singleShot) request.setNumUpdates(1);
return request;
}
@@ -220,16 +224,17 @@
}
LocationRequest request = new LocationRequest()
- .setQuality(quality)
- .setInterval(minTime)
- .setFastestInterval(minTime)
- .setSmallestDisplacement(minDistance);
+ .setQuality(quality)
+ .setInterval(minTime)
+ .setFastestInterval(minTime)
+ .setSmallestDisplacement(minDistance);
if (singleShot) request.setNumUpdates(1);
return request;
}
/** @hide */
- public LocationRequest() { }
+ public LocationRequest() {
+ }
/** @hide */
public LocationRequest(LocationRequest src) {
@@ -243,6 +248,7 @@
mProvider = src.mProvider;
mWorkSource = src.mWorkSource;
mHideFromAppOps = src.mHideFromAppOps;
+ mLowPowerMode = src.mLowPowerMode;
}
/**
@@ -263,8 +269,8 @@
* on a location request.
*
* @param quality an accuracy or power constant
- * @throws InvalidArgumentException if the quality constant is not valid
* @return the same object, so that setters can be chained
+ * @throws InvalidArgumentException if the quality constant is not valid
*/
public LocationRequest setQuality(int quality) {
checkQuality(quality);
@@ -306,14 +312,14 @@
* on a location request.
*
* @param millis desired interval in millisecond, inexact
- * @throws InvalidArgumentException if the interval is less than zero
* @return the same object, so that setters can be chained
+ * @throws InvalidArgumentException if the interval is less than zero
*/
public LocationRequest setInterval(long millis) {
checkInterval(millis);
mInterval = millis;
if (!mExplicitFastestInterval) {
- mFastestInterval = (long)(mInterval / FASTEST_INTERVAL_FACTOR);
+ mFastestInterval = (long) (mInterval / FASTEST_INTERVAL_FACTOR);
}
return this;
}
@@ -327,6 +333,34 @@
return mInterval;
}
+
+ /**
+ * Requests the GNSS chipset to run in a low power mode and make strong tradeoffs to
+ * substantially restrict power.
+ *
+ * <p>In this mode, the GNSS chipset will not, on average, run power hungry operations like RF &
+ * signal searches for more than one second per interval {@link #mInterval}
+ *
+ * @param enabled Enable or disable low power mode
+ * @return the same object, so that setters can be chained
+ * @hide
+ */
+ @SystemApi
+ public LocationRequest setLowPowerMode(boolean enabled) {
+ mLowPowerMode = enabled;
+ return this;
+ }
+
+ /**
+ * Returns true if low power mode is enabled.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isLowPowerMode() {
+ return mLowPowerMode;
+ }
+
/**
* Explicitly set the fastest interval for location updates, in
* milliseconds.
@@ -353,8 +387,8 @@
* then your effective fastest interval is {@link #setInterval}.
*
* @param millis fastest interval for updates in milliseconds, exact
- * @throws InvalidArgumentException if the interval is less than zero
* @return the same object, so that setters can be chained
+ * @throws InvalidArgumentException if the interval is less than zero
*/
public LocationRequest setFastestInterval(long millis) {
checkInterval(millis);
@@ -397,9 +431,9 @@
// Check for > Long.MAX_VALUE overflow (elapsedRealtime > 0):
if (millis > Long.MAX_VALUE - elapsedRealtime) {
- mExpireAt = Long.MAX_VALUE;
+ mExpireAt = Long.MAX_VALUE;
} else {
- mExpireAt = millis + elapsedRealtime;
+ mExpireAt = millis + elapsedRealtime;
}
if (mExpireAt < 0) mExpireAt = 0;
@@ -448,11 +482,14 @@
* to the location manager.
*
* @param numUpdates the number of location updates requested
- * @throws InvalidArgumentException if numUpdates is 0 or less
* @return the same object, so that setters can be chained
+ * @throws InvalidArgumentException if numUpdates is 0 or less
*/
public LocationRequest setNumUpdates(int numUpdates) {
- if (numUpdates <= 0) throw new IllegalArgumentException("invalid numUpdates: " + numUpdates);
+ if (numUpdates <= 0) {
+ throw new IllegalArgumentException(
+ "invalid numUpdates: " + numUpdates);
+ }
mNumUpdates = numUpdates;
return this;
}
@@ -462,6 +499,7 @@
*
* <p>By default this is {@link Integer#MAX_VALUE}, which indicates that
* locations are updated until the request is explicitly removed.
+ *
* @return number of updates
*/
public int getNumUpdates() {
@@ -539,8 +577,8 @@
* doesn't have the {@link android.Manifest.permission#UPDATE_APP_OPS_STATS} permission.
*
* @param hideFromAppOps If true AppOps won't keep track of this location request.
- * @see android.app.AppOpsManager
* @hide
+ * @see android.app.AppOpsManager
*/
@SystemApi
public void setHideFromAppOps(boolean hideFromAppOps) {
@@ -587,27 +625,29 @@
public static final Parcelable.Creator<LocationRequest> CREATOR =
new Parcelable.Creator<LocationRequest>() {
- @Override
- public LocationRequest createFromParcel(Parcel in) {
- LocationRequest request = new LocationRequest();
- request.setQuality(in.readInt());
- request.setFastestInterval(in.readLong());
- request.setInterval(in.readLong());
- request.setExpireAt(in.readLong());
- request.setNumUpdates(in.readInt());
- request.setSmallestDisplacement(in.readFloat());
- request.setHideFromAppOps(in.readInt() != 0);
- String provider = in.readString();
- if (provider != null) request.setProvider(provider);
- WorkSource workSource = in.readParcelable(null);
- if (workSource != null) request.setWorkSource(workSource);
- return request;
- }
- @Override
- public LocationRequest[] newArray(int size) {
- return new LocationRequest[size];
- }
- };
+ @Override
+ public LocationRequest createFromParcel(Parcel in) {
+ LocationRequest request = new LocationRequest();
+ request.setQuality(in.readInt());
+ request.setFastestInterval(in.readLong());
+ request.setInterval(in.readLong());
+ request.setExpireAt(in.readLong());
+ request.setNumUpdates(in.readInt());
+ request.setSmallestDisplacement(in.readFloat());
+ request.setHideFromAppOps(in.readInt() != 0);
+ request.setLowPowerMode(in.readInt() != 0);
+ String provider = in.readString();
+ if (provider != null) request.setProvider(provider);
+ WorkSource workSource = in.readParcelable(null);
+ if (workSource != null) request.setWorkSource(workSource);
+ return request;
+ }
+
+ @Override
+ public LocationRequest[] newArray(int size) {
+ return new LocationRequest[size];
+ }
+ };
@Override
public int describeContents() {
@@ -623,6 +663,7 @@
parcel.writeInt(mNumUpdates);
parcel.writeFloat(mSmallestDisplacement);
parcel.writeInt(mHideFromAppOps ? 1 : 0);
+ parcel.writeInt(mLowPowerMode ? 1 : 0);
parcel.writeString(mProvider);
parcel.writeParcelable(mWorkSource, 0);
}
@@ -663,9 +704,10 @@
s.append(" expireIn=");
TimeUtils.formatDuration(expireIn, s);
}
- if (mNumUpdates != Integer.MAX_VALUE){
+ if (mNumUpdates != Integer.MAX_VALUE) {
s.append(" num=").append(mNumUpdates);
}
+ s.append(" lowPowerMode=").append(mLowPowerMode);
s.append(']');
return s.toString();
}
diff --git a/location/java/com/android/internal/location/ProviderRequest.java b/location/java/com/android/internal/location/ProviderRequest.java
index 26243e7..45fdb76 100644
--- a/location/java/com/android/internal/location/ProviderRequest.java
+++ b/location/java/com/android/internal/location/ProviderRequest.java
@@ -33,6 +33,12 @@
public long interval = Long.MAX_VALUE;
/**
+ * Whether provider shall make stronger than normal tradeoffs to substantially restrict power
+ * use.
+ */
+ public boolean lowPowerMode = false;
+
+ /**
* A more detailed set of requests.
* <p>Location Providers can optionally use this to
* fine tune location updates, for example when there
@@ -41,26 +47,29 @@
*/
public List<LocationRequest> locationRequests = new ArrayList<LocationRequest>();
- public ProviderRequest() { }
+ public ProviderRequest() {
+ }
public static final Parcelable.Creator<ProviderRequest> CREATOR =
new Parcelable.Creator<ProviderRequest>() {
- @Override
- public ProviderRequest createFromParcel(Parcel in) {
- ProviderRequest request = new ProviderRequest();
- request.reportLocation = in.readInt() == 1;
- request.interval = in.readLong();
- int count = in.readInt();
- for (int i = 0; i < count; i++) {
- request.locationRequests.add(LocationRequest.CREATOR.createFromParcel(in));
- }
- return request;
- }
- @Override
- public ProviderRequest[] newArray(int size) {
- return new ProviderRequest[size];
- }
- };
+ @Override
+ public ProviderRequest createFromParcel(Parcel in) {
+ ProviderRequest request = new ProviderRequest();
+ request.reportLocation = in.readInt() == 1;
+ request.interval = in.readLong();
+ request.lowPowerMode = in.readBoolean();
+ int count = in.readInt();
+ for (int i = 0; i < count; i++) {
+ request.locationRequests.add(LocationRequest.CREATOR.createFromParcel(in));
+ }
+ return request;
+ }
+
+ @Override
+ public ProviderRequest[] newArray(int size) {
+ return new ProviderRequest[size];
+ }
+ };
@Override
public int describeContents() {
@@ -71,6 +80,7 @@
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(reportLocation ? 1 : 0);
parcel.writeLong(interval);
+ parcel.writeBoolean(lowPowerMode);
parcel.writeInt(locationRequests.size());
for (LocationRequest request : locationRequests) {
request.writeToParcel(parcel, flags);
@@ -85,6 +95,7 @@
s.append("ON");
s.append(" interval=");
TimeUtils.formatDuration(interval, s);
+ s.append(" lowPowerMode=" + lowPowerMode);
} else {
s.append("OFF");
}
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/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 1b89c96..19d467a 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -127,6 +127,14 @@
}
/**
+ * @hide
+ * @return The underlying {@link AudioDevicePort} instance.
+ */
+ public AudioDevicePort getPort() {
+ return mPort;
+ }
+
+ /**
* @return The internal device ID.
*/
public int getId() {
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/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 12e5744..e2f9b47 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -977,7 +977,7 @@
public static final String PROPERTY_ALGORITHMS = "algorithms";
/** @hide */
- @StringDef({
+ @StringDef(prefix = { "PROPERTY_" }, value = {
PROPERTY_VENDOR,
PROPERTY_VERSION,
PROPERTY_DESCRIPTION,
@@ -1010,7 +1010,7 @@
public static final String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
/** @hide */
- @StringDef({
+ @StringDef(prefix = { "PROPERTY_" }, value = {
PROPERTY_DEVICE_UNIQUE_ID,
})
@Retention(RetentionPolicy.SOURCE)
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index 31eb948..94d4d55 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -45,34 +45,61 @@
/**
* @hide
*/
- @StringDef({METADATA_KEY_TITLE, METADATA_KEY_ARTIST, METADATA_KEY_ALBUM, METADATA_KEY_AUTHOR,
- METADATA_KEY_WRITER, METADATA_KEY_COMPOSER, METADATA_KEY_COMPILATION,
- METADATA_KEY_DATE, METADATA_KEY_GENRE, METADATA_KEY_ALBUM_ARTIST, METADATA_KEY_ART_URI,
- METADATA_KEY_ALBUM_ART_URI, METADATA_KEY_DISPLAY_TITLE, METADATA_KEY_DISPLAY_SUBTITLE,
- METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_KEY_DISPLAY_ICON_URI,
- METADATA_KEY_MEDIA_ID, METADATA_KEY_MEDIA_URI})
+ @StringDef(prefix = { "METADATA_KEY_" }, value = {
+ METADATA_KEY_TITLE,
+ METADATA_KEY_ARTIST,
+ METADATA_KEY_ALBUM,
+ METADATA_KEY_AUTHOR,
+ METADATA_KEY_WRITER,
+ METADATA_KEY_COMPOSER,
+ METADATA_KEY_COMPILATION,
+ METADATA_KEY_DATE,
+ METADATA_KEY_GENRE,
+ METADATA_KEY_ALBUM_ARTIST,
+ METADATA_KEY_ART_URI,
+ METADATA_KEY_ALBUM_ART_URI,
+ METADATA_KEY_DISPLAY_TITLE,
+ METADATA_KEY_DISPLAY_SUBTITLE,
+ METADATA_KEY_DISPLAY_DESCRIPTION,
+ METADATA_KEY_DISPLAY_ICON_URI,
+ METADATA_KEY_MEDIA_ID,
+ METADATA_KEY_MEDIA_URI,
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface TextKey {}
/**
* @hide
*/
- @StringDef({METADATA_KEY_DURATION, METADATA_KEY_YEAR, METADATA_KEY_TRACK_NUMBER,
- METADATA_KEY_NUM_TRACKS, METADATA_KEY_DISC_NUMBER, METADATA_KEY_BT_FOLDER_TYPE})
+ @StringDef(prefix = { "METADATA_KEY_" }, value = {
+ METADATA_KEY_DURATION,
+ METADATA_KEY_YEAR,
+ METADATA_KEY_TRACK_NUMBER,
+ METADATA_KEY_NUM_TRACKS,
+ METADATA_KEY_DISC_NUMBER,
+ METADATA_KEY_BT_FOLDER_TYPE,
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface LongKey {}
/**
* @hide
*/
- @StringDef({METADATA_KEY_ART, METADATA_KEY_ALBUM_ART, METADATA_KEY_DISPLAY_ICON})
+ @StringDef(prefix = { "METADATA_KEY_" }, value = {
+ METADATA_KEY_ART,
+ METADATA_KEY_ALBUM_ART,
+ METADATA_KEY_DISPLAY_ICON,
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface BitmapKey {}
/**
* @hide
*/
- @StringDef({METADATA_KEY_USER_RATING, METADATA_KEY_RATING})
+ @StringDef(prefix = { "METADATA_KEY_" }, value = {
+ METADATA_KEY_USER_RATING,
+ METADATA_KEY_RATING,
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface RatingKey {}
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/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/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 8283c8b..17d16b8 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -17,6 +17,7 @@
import android.annotation.DrawableRes;
import android.annotation.IntDef;
+import android.annotation.LongDef;
import android.annotation.Nullable;
import android.media.RemoteControlClient;
import android.os.Bundle;
@@ -41,7 +42,7 @@
/**
* @hide
*/
- @IntDef(flag=true, value={ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
+ @LongDef(flag=true, value={ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING,
ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 0f46096..3bbc2c4 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1650,7 +1650,7 @@
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel";
/** @hide */
- @StringDef({
+ @StringDef(prefix = { "TYPE_" }, value = {
TYPE_OTHER,
TYPE_NTSC,
TYPE_PAL,
@@ -1863,7 +1863,7 @@
public static final String TYPE_PREVIEW = "TYPE_PREVIEW";
/** @hide */
- @StringDef({
+ @StringDef(prefix = { "SERVICE_TYPE_" }, value = {
SERVICE_TYPE_OTHER,
SERVICE_TYPE_AUDIO_VIDEO,
SERVICE_TYPE_AUDIO,
@@ -1881,7 +1881,7 @@
public static final String SERVICE_TYPE_AUDIO = "SERVICE_TYPE_AUDIO";
/** @hide */
- @StringDef({
+ @StringDef(prefix = { "VIDEO_FORMAT_" }, value = {
VIDEO_FORMAT_240P,
VIDEO_FORMAT_360P,
VIDEO_FORMAT_480I,
@@ -1930,7 +1930,7 @@
public static final String VIDEO_FORMAT_4320P = "VIDEO_FORMAT_4320P";
/** @hide */
- @StringDef({
+ @StringDef(prefix = { "VIDEO_RESOLUTION_" }, value = {
VIDEO_RESOLUTION_SD,
VIDEO_RESOLUTION_ED,
VIDEO_RESOLUTION_HD,
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_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..b4ca88c 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -24,8 +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"
#include <media/AudioPolicyHelper.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/media/mca/tests/Android.mk b/media/mca/tests/Android.mk
index eb451f7..394f542 100644
--- a/media/mca/tests/Android.mk
+++ b/media/mca/tests/Android.mk
@@ -4,8 +4,8 @@
# We only want this apk build for tests.
LOCAL_MODULE_TAGS := tests
-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 all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
index 0d9f42b..145cde6 100644
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ b/media/tests/MediaFrameworkTest/Android.mk
@@ -5,13 +5,12 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_STATIC_JAVA_LIBRARIES := \
mockito-target-minus-junit4 \
android-support-test \
- android-ex-camera2 \
- legacy-android-test
+ android-ex-camera2
LOCAL_PACKAGE_NAME := mediaframeworktest
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index e628b68..fadb76d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -16,10 +16,18 @@
package com.android.mediaframeworktest.integration;
+import static android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.argThat;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.ICameraService;
-import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
@@ -41,13 +49,10 @@
import android.util.Log;
import android.view.Surface;
-import static android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW;
-
import com.android.mediaframeworktest.MediaFrameworkIntegrationTestRunner;
import org.mockito.ArgumentCaptor;
-import org.mockito.compat.ArgumentMatcher;
-import static org.mockito.Mockito.*;
+import org.mockito.ArgumentMatcher;
public class CameraDeviceBinderTest extends AndroidTestCase {
private static String TAG = "CameraDeviceBinderTest";
@@ -166,10 +171,10 @@
}
}
- class IsMetadataNotEmpty extends ArgumentMatcher<CameraMetadataNative> {
+ class IsMetadataNotEmpty implements ArgumentMatcher<CameraMetadataNative> {
@Override
- public boolean matchesObject(Object obj) {
- return !((CameraMetadataNative) obj).isEmpty();
+ public boolean matches(CameraMetadataNative obj) {
+ return !obj.isEmpty();
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
index 712039d..74bf1a2 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
@@ -16,13 +16,13 @@
package com.android.mediaframeworktest.unit;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
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 static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
import android.content.ContentProviderClient;
import android.content.ContentValues;
@@ -36,10 +36,9 @@
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
-import org.hamcrest.Description;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.compat.ArgumentMatcher;
public class MediaInserterTest extends InstrumentationTestCase {
@@ -59,7 +58,7 @@
private static final Uri sImagesUri = Images.Media.getContentUri(sVolumeName);
private static final Uri sFilesUri = Files.getContentUri(sVolumeName);
- private static class MediaUriMatcher extends ArgumentMatcher<Uri> {
+ private static class MediaUriMatcher implements ArgumentMatcher<Uri> {
private final Uri mUri;
private MediaUriMatcher(Uri uri) {
@@ -67,15 +66,8 @@
}
@Override
- public boolean matchesObject(Object argument) {
- if (!(argument instanceof Uri)) {
- return false;
- }
-
- Uri actualUri = (Uri) argument;
- if (actualUri == mUri)
- return true;
- return false;
+ public boolean matches(Uri actualUri) {
+ return actualUri == mUri;
}
@Override
diff --git a/nfc-extras/tests/Android.mk b/nfc-extras/tests/Android.mk
index d8fe5a6..be2bb53 100644
--- a/nfc-extras/tests/Android.mk
+++ b/nfc-extras/tests/Android.mk
@@ -22,7 +22,7 @@
android.test.runner \
com.android.nfc_extras
-LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
+LOCAL_STATIC_JAVA_LIBRARIES := junit
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
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/CaptivePortalLogin/OWNERS b/packages/CaptivePortalLogin/OWNERS
index 2d71c20..6f77e04 100644
--- a/packages/CaptivePortalLogin/OWNERS
+++ b/packages/CaptivePortalLogin/OWNERS
@@ -1,10 +1,7 @@
set noparent
-per-file Android.mk = build.master@android.com
-per-file Android.mk = ek@google.com
-per-file Android.mk = hugobenichi@google.com
-per-file Android.mk = lorenzo@google.com
-
ek@google.com
hugobenichi@google.com
+jchalard@google.com
lorenzo@google.com
+satk@google.com
diff --git a/packages/CarrierDefaultApp/tests/unit/Android.mk b/packages/CarrierDefaultApp/tests/unit/Android.mk
index 63bd0b1..6e120a6 100644
--- a/packages/CarrierDefaultApp/tests/unit/Android.mk
+++ b/packages/CarrierDefaultApp/tests/unit/Android.mk
@@ -19,9 +19,9 @@
LOCAL_MODULE_TAGS := tests
LOCAL_CERTIFICATE := platform
-LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
+LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.test.base
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target-minus-junit4 legacy-android-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target-minus-junit4
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
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/ExtServices/tests/Android.mk b/packages/ExtServices/tests/Android.mk
index 92afbeb..1eb5847 100644
--- a/packages/ExtServices/tests/Android.mk
+++ b/packages/ExtServices/tests/Android.mk
@@ -5,14 +5,13 @@
LOCAL_MODULE_TAGS := tests
LOCAL_CERTIFICATE := platform
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
mockito-target-minus-junit4 \
espresso-core \
truth-prebuilt \
- legacy-android-test \
testables
# Include all test java files.
diff --git a/packages/InputDevices/res/raw/keyboard_layout_azerbaijani.kcm b/packages/InputDevices/res/raw/keyboard_layout_azerbaijani.kcm
new file mode 100644
index 0000000..69490cc
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_azerbaijani.kcm
@@ -0,0 +1,312 @@
+# 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.
+
+#
+# Azerbaijan (AZ) keyboard layout.
+#
+
+type OVERLAY
+
+### ROW 1
+
+key GRAVE {
+ label: '`'
+ base: '`'
+ shift: '~'
+}
+
+key 1 {
+ label: '1'
+ base: '1'
+ shift: '!'
+}
+
+key 2 {
+ label: '2'
+ base: '2'
+ shift: '"'
+ ralt: '@'
+}
+
+key 3 {
+ label: '3'
+ base: '3'
+ shift: '\u2166'
+}
+
+key 4 {
+ label: '4'
+ base: '4'
+ shift: ';'
+}
+
+key 5 {
+ label: '5'
+ base: '5'
+ shift: '%'
+}
+
+key 6 {
+ label: '6'
+ base: '6'
+ shift: ':'
+ shift+ralt: '^'
+}
+
+key 7 {
+ label: '7'
+ base: '7'
+ shift: '?'
+ ralt: '&'
+}
+
+key 8 {
+ label: '8'
+ base: '8'
+ shift: '*'
+}
+
+key 9 {
+ label: '9'
+ base: '9'
+ shift: '('
+}
+
+key 0 {
+ label: '0'
+ base: '0'
+ shift: ')'
+}
+
+key MINUS {
+ label: '-'
+ base: '-'
+ shift: '_'
+}
+
+key EQUALS {
+ label: '='
+ base: '='
+ shift: '+'
+}
+
+### ROW 2
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+}
+
+key W {
+ label: '\u00dc'
+ base: '\u00fc'
+ shift, capslock: '\u00dc'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+}
+
+key I {
+ label: '\u0130'
+ base: 'i'
+ shift, capslock: '\u0130'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '\u00d6'
+ base: '\u00f6'
+ shift: '\u00d6'
+}
+
+key RIGHT_BRACKET {
+ label: '\u011e'
+ base: '\u011f'
+ shift: '\u011e'
+}
+
+key BACKSLASH {
+ label: '\\'
+ base: '\\'
+ shift: '|'
+}
+
+### ROW 3
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+}
+
+key SEMICOLON {
+ label: 'I'
+ base: '\u0131'
+ shift: 'I'
+}
+
+key APOSTROPHE {
+ label: '\u018f'
+ base: '\u0259'
+ shift: '\u018f'
+}
+
+### ROW 4
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+}
+
+key COMMA {
+ label: '\u00c7'
+ base: '\u00e7'
+ shift: '\u00c7'
+}
+
+key PERIOD {
+ label: '\u015e'
+ base: '\u015f'
+ shift: '\u015e'
+}
+
+key SLASH {
+ label: '.'
+ base: '.'
+ shift: ','
+}
diff --git a/packages/InputDevices/res/values-af/strings.xml b/packages/InputDevices/res/values-af/strings.xml
index 4301019..badeb6d 100644
--- a/packages/InputDevices/res/values-af/strings.xml
+++ b/packages/InputDevices/res/values-af/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spaans (Latyn)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letties"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persies"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Aserbeidjaans"</string>
</resources>
diff --git a/packages/InputDevices/res/values-am/strings.xml b/packages/InputDevices/res/values-am/strings.xml
index ce3659a..2375bd4 100644
--- a/packages/InputDevices/res/values-am/strings.xml
+++ b/packages/InputDevices/res/values-am/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ስፓኒሽ (ላቲን)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"ላትቪያኛ"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"ፋርስኛ"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"አዘርባይጃንኛ"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ar/strings.xml b/packages/InputDevices/res/values-ar/strings.xml
index 2b0a6f9..0263a68 100644
--- a/packages/InputDevices/res/values-ar/strings.xml
+++ b/packages/InputDevices/res/values-ar/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"الإسبانية (اللاتينية)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"اللاتفية"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"الفارسية"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"الأذربيجانية"</string>
</resources>
diff --git a/packages/InputDevices/res/values-az/strings.xml b/packages/InputDevices/res/values-az/strings.xml
index a1f7c1c..e0286ee 100644
--- a/packages/InputDevices/res/values-az/strings.xml
+++ b/packages/InputDevices/res/values-az/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"İspan (Latın)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latış"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Fars Dili"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azəri"</string>
</resources>
diff --git a/packages/InputDevices/res/values-b+sr+Latn/strings.xml b/packages/InputDevices/res/values-b+sr+Latn/strings.xml
index c60b59e..bc9330d 100644
--- a/packages/InputDevices/res/values-b+sr+Latn/strings.xml
+++ b/packages/InputDevices/res/values-b+sr+Latn/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španski (Latinska Amerika)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"letonski"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"persijska"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"azerbejdžanska"</string>
</resources>
diff --git a/packages/InputDevices/res/values-be/strings.xml b/packages/InputDevices/res/values-be/strings.xml
index e93d03a..cfe078e 100644
--- a/packages/InputDevices/res/values-be/strings.xml
+++ b/packages/InputDevices/res/values-be/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Іспанская (Лацінская Амерыка)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Латышская"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Персідская"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Азербайджанская"</string>
</resources>
diff --git a/packages/InputDevices/res/values-bg/strings.xml b/packages/InputDevices/res/values-bg/strings.xml
index ee5cfa8..a520a80 100644
--- a/packages/InputDevices/res/values-bg/strings.xml
+++ b/packages/InputDevices/res/values-bg/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Исп. клав. подредба (Лат. Америка)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"латвийски"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"персийски"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"азербайджански"</string>
</resources>
diff --git a/packages/InputDevices/res/values-bn/strings.xml b/packages/InputDevices/res/values-bn/strings.xml
index 945c891..5f8877a 100644
--- a/packages/InputDevices/res/values-bn/strings.xml
+++ b/packages/InputDevices/res/values-bn/strings.xml
@@ -42,4 +42,6 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"স্প্যানিশ (ল্যাটিন)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"লাটভিও"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"ফার্সী"</string>
+ <!-- no translation found for keyboard_layout_azerbaijani (7315895417176467567) -->
+ <skip />
</resources>
diff --git a/packages/InputDevices/res/values-bs/strings.xml b/packages/InputDevices/res/values-bs/strings.xml
index ca1b8ff..c16b266 100644
--- a/packages/InputDevices/res/values-bs/strings.xml
+++ b/packages/InputDevices/res/values-bs/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španski (Latinska Amerika)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"latvijski"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"perzijski"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"azerbejdžanski"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ca/strings.xml b/packages/InputDevices/res/values-ca/strings.xml
index 3c6ea15..fe8e809 100644
--- a/packages/InputDevices/res/values-ca/strings.xml
+++ b/packages/InputDevices/res/values-ca/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanyol (llatí)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letó"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persa"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Àzeri"</string>
</resources>
diff --git a/packages/InputDevices/res/values-cs/strings.xml b/packages/InputDevices/res/values-cs/strings.xml
index a78663b..a571f94 100644
--- a/packages/InputDevices/res/values-cs/strings.xml
+++ b/packages/InputDevices/res/values-cs/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španělština (Latinská Amerika)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Lotyšská klávesnice"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"perština"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"ázerbájdžánština"</string>
</resources>
diff --git a/packages/InputDevices/res/values-da/strings.xml b/packages/InputDevices/res/values-da/strings.xml
index 08ff4ca..1943d35 100644
--- a/packages/InputDevices/res/values-da/strings.xml
+++ b/packages/InputDevices/res/values-da/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spansk (latinamerika)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Lettisk"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persisk"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Aserbajdsjansk"</string>
</resources>
diff --git a/packages/InputDevices/res/values-de/strings.xml b/packages/InputDevices/res/values-de/strings.xml
index 1543ef2..418a3f0 100644
--- a/packages/InputDevices/res/values-de/strings.xml
+++ b/packages/InputDevices/res/values-de/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanisch (Lateinisch)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Lettisch"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persisch"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Aserbaidschanisch"</string>
</resources>
diff --git a/packages/InputDevices/res/values-el/strings.xml b/packages/InputDevices/res/values-el/strings.xml
index e5d1409..460d0f8 100644
--- a/packages/InputDevices/res/values-el/strings.xml
+++ b/packages/InputDevices/res/values-el/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Ισπανικά (Λατινικής Αμερικής)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Λετονικά"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Περσικά"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Αζερμπαϊτζανικά"</string>
</resources>
diff --git a/packages/InputDevices/res/values-es-rUS/strings.xml b/packages/InputDevices/res/values-es-rUS/strings.xml
index 68fcfd7..e6c12a7 100644
--- a/packages/InputDevices/res/values-es-rUS/strings.xml
+++ b/packages/InputDevices/res/values-es-rUS/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Español (latino)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letón"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persa"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerí"</string>
</resources>
diff --git a/packages/InputDevices/res/values-es/strings.xml b/packages/InputDevices/res/values-es/strings.xml
index 86c82ed..7f779c0 100644
--- a/packages/InputDevices/res/values-es/strings.xml
+++ b/packages/InputDevices/res/values-es/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Español (Latinoamérica)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letón"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persa"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerí"</string>
</resources>
diff --git a/packages/InputDevices/res/values-et/strings.xml b/packages/InputDevices/res/values-et/strings.xml
index 8bc5c25..a5d8cf9 100644
--- a/packages/InputDevices/res/values-et/strings.xml
+++ b/packages/InputDevices/res/values-et/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Hispaania (Ladina-Ameerika)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"läti keel"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"pärsia"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"aserbaidžaani"</string>
</resources>
diff --git a/packages/InputDevices/res/values-eu/strings.xml b/packages/InputDevices/res/values-eu/strings.xml
index 4fadb97..8d62b34 100644
--- a/packages/InputDevices/res/values-eu/strings.xml
+++ b/packages/InputDevices/res/values-eu/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espainiera (Latinoamerika)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letoniera"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Pertsiera"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijanera"</string>
</resources>
diff --git a/packages/InputDevices/res/values-fa/strings.xml b/packages/InputDevices/res/values-fa/strings.xml
index 037e044..6effa27 100644
--- a/packages/InputDevices/res/values-fa/strings.xml
+++ b/packages/InputDevices/res/values-fa/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"اسپانیایی (لاتین)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"لتونیایی"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"فارسی"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"آذربایجانی"</string>
</resources>
diff --git a/packages/InputDevices/res/values-fi/strings.xml b/packages/InputDevices/res/values-fi/strings.xml
index 65bd8d3..9530df6 100644
--- a/packages/InputDevices/res/values-fi/strings.xml
+++ b/packages/InputDevices/res/values-fi/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"espanja (Latinalainen Amerikka)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"latvialainen"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"persia"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"azeri"</string>
</resources>
diff --git a/packages/InputDevices/res/values-fr-rCA/strings.xml b/packages/InputDevices/res/values-fr-rCA/strings.xml
index 8b132fa..afb61fd 100644
--- a/packages/InputDevices/res/values-fr-rCA/strings.xml
+++ b/packages/InputDevices/res/values-fr-rCA/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espagnol (latin)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letton"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persan"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaïdjanais"</string>
</resources>
diff --git a/packages/InputDevices/res/values-fr/strings.xml b/packages/InputDevices/res/values-fr/strings.xml
index baf749d..fadc6a2 100644
--- a/packages/InputDevices/res/values-fr/strings.xml
+++ b/packages/InputDevices/res/values-fr/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espagnol (latin)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letton"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persan"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azéri"</string>
</resources>
diff --git a/packages/InputDevices/res/values-gl/strings.xml b/packages/InputDevices/res/values-gl/strings.xml
index c5bddc5..de7adf1 100644
--- a/packages/InputDevices/res/values-gl/strings.xml
+++ b/packages/InputDevices/res/values-gl/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Español (América Latina)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letón"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persa"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Acerbaixano"</string>
</resources>
diff --git a/packages/InputDevices/res/values-gu/strings.xml b/packages/InputDevices/res/values-gu/strings.xml
index 0f8c752..d11df01 100644
--- a/packages/InputDevices/res/values-gu/strings.xml
+++ b/packages/InputDevices/res/values-gu/strings.xml
@@ -42,4 +42,6 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"સ્પેનિશ (લેટિન)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"લાતવિયન"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"પર્શિયન"</string>
+ <!-- no translation found for keyboard_layout_azerbaijani (7315895417176467567) -->
+ <skip />
</resources>
diff --git a/packages/InputDevices/res/values-hi/strings.xml b/packages/InputDevices/res/values-hi/strings.xml
index c1bbd9d..0abcf87 100644
--- a/packages/InputDevices/res/values-hi/strings.xml
+++ b/packages/InputDevices/res/values-hi/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"स्पेनिश (लैटिन)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"लातवियाई"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"फ़ारसी"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"अज़रबैजानी"</string>
</resources>
diff --git a/packages/InputDevices/res/values-hr/strings.xml b/packages/InputDevices/res/values-hr/strings.xml
index ec02934..7b27449b 100644
--- a/packages/InputDevices/res/values-hr/strings.xml
+++ b/packages/InputDevices/res/values-hr/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španjolski (Latinska Amerika)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"latvijska"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"perzijski"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"azerbajdžanski"</string>
</resources>
diff --git a/packages/InputDevices/res/values-hu/strings.xml b/packages/InputDevices/res/values-hu/strings.xml
index a5412d4..20a0a4f 100644
--- a/packages/InputDevices/res/values-hu/strings.xml
+++ b/packages/InputDevices/res/values-hu/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"spanyol (latin-amerikai)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"lett"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"perzsa"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"azeri"</string>
</resources>
diff --git a/packages/InputDevices/res/values-hy/strings.xml b/packages/InputDevices/res/values-hy/strings.xml
index b152b0f..e2c485c 100644
--- a/packages/InputDevices/res/values-hy/strings.xml
+++ b/packages/InputDevices/res/values-hy/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Իսպաներեն (Լատինական)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"լատիշերեն"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"պարսկերեն"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"ադրբեջաներեն"</string>
</resources>
diff --git a/packages/InputDevices/res/values-in/strings.xml b/packages/InputDevices/res/values-in/strings.xml
index 33b9ae3..5e45207 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>
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanyol (Latin)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvi"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persia"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijan"</string>
</resources>
diff --git a/packages/InputDevices/res/values-is/strings.xml b/packages/InputDevices/res/values-is/strings.xml
index 0e80bd4..25eeea3 100644
--- a/packages/InputDevices/res/values-is/strings.xml
+++ b/packages/InputDevices/res/values-is/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spænskt (latneskt)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Lettneska"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persneska"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"aserska"</string>
</resources>
diff --git a/packages/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml
index 5da935b..4380d48 100644
--- a/packages/InputDevices/res/values-it/strings.xml
+++ b/packages/InputDevices/res/values-it/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spagnolo (America Latina)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Lettone"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persiano"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azero"</string>
</resources>
diff --git a/packages/InputDevices/res/values-iw/strings.xml b/packages/InputDevices/res/values-iw/strings.xml
index 5cbc4f4..27f1611 100644
--- a/packages/InputDevices/res/values-iw/strings.xml
+++ b/packages/InputDevices/res/values-iw/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ספרדית (לטינית)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"לטבית"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"פרסית"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"אזרית"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ja/strings.xml b/packages/InputDevices/res/values-ja/strings.xml
index aa77ddc..c0c6915 100644
--- a/packages/InputDevices/res/values-ja/strings.xml
+++ b/packages/InputDevices/res/values-ja/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"スペイン語(中南米)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"ラトビア語"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"ペルシャ語"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"アゼルバイジャン語"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ka/strings.xml b/packages/InputDevices/res/values-ka/strings.xml
index 0b899c7..471d808 100644
--- a/packages/InputDevices/res/values-ka/strings.xml
+++ b/packages/InputDevices/res/values-ka/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ესპანური (ლათინური)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"ლატვიური"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"სპარსული"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"აზერბაიჯანული"</string>
</resources>
diff --git a/packages/InputDevices/res/values-kk/strings.xml b/packages/InputDevices/res/values-kk/strings.xml
index 659f571..4688ebc 100644
--- a/packages/InputDevices/res/values-kk/strings.xml
+++ b/packages/InputDevices/res/values-kk/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Испан (латын)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Латыш"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Парсы"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"әзiрбайжан"</string>
</resources>
diff --git a/packages/InputDevices/res/values-km/strings.xml b/packages/InputDevices/res/values-km/strings.xml
index a3a789c..fca3737 100644
--- a/packages/InputDevices/res/values-km/strings.xml
+++ b/packages/InputDevices/res/values-km/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"អេស្ប៉ាញ (ឡាតាំង)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"ឡាតវីយ៉ា"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"ពីស៊ាន"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"អាហ្សឺបៃហ្សង់"</string>
</resources>
diff --git a/packages/InputDevices/res/values-kn/strings.xml b/packages/InputDevices/res/values-kn/strings.xml
index f07b439..2e6f892 100644
--- a/packages/InputDevices/res/values-kn/strings.xml
+++ b/packages/InputDevices/res/values-kn/strings.xml
@@ -42,4 +42,6 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ಸ್ಪ್ಯಾನಿಶ್ (ಲ್ಯಾಟಿನ್)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"ಲ್ಯಾಟ್ವಿಯನ್"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"ಪರ್ಶಿಯನ್"</string>
+ <!-- no translation found for keyboard_layout_azerbaijani (7315895417176467567) -->
+ <skip />
</resources>
diff --git a/packages/InputDevices/res/values-ko/strings.xml b/packages/InputDevices/res/values-ko/strings.xml
index 28dde45..f712332 100644
--- a/packages/InputDevices/res/values-ko/strings.xml
+++ b/packages/InputDevices/res/values-ko/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"스페인어(라틴)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"라트비아어"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"페르시아어"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"아제르바이잔어"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ky/strings.xml b/packages/InputDevices/res/values-ky/strings.xml
index e12b69f..5b3e986 100644
--- a/packages/InputDevices/res/values-ky/strings.xml
+++ b/packages/InputDevices/res/values-ky/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Испанча (Латын)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Латвияча"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Фарсиче"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Азербайжанча"</string>
</resources>
diff --git a/packages/InputDevices/res/values-lo/strings.xml b/packages/InputDevices/res/values-lo/strings.xml
index 8c040be..e64d83d 100644
--- a/packages/InputDevices/res/values-lo/strings.xml
+++ b/packages/InputDevices/res/values-lo/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ສະແປນນິດ (ລາຕິນ)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"ລັດວຽນ"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"ເປີຊຽນ"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"ອາເຊີໄບຈານີ"</string>
</resources>
diff --git a/packages/InputDevices/res/values-lt/strings.xml b/packages/InputDevices/res/values-lt/strings.xml
index 0cd696f..a92ddaf 100644
--- a/packages/InputDevices/res/values-lt/strings.xml
+++ b/packages/InputDevices/res/values-lt/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Ispanų (Lotynų Amerika)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvių k."</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persų"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaidžaniečių"</string>
</resources>
diff --git a/packages/InputDevices/res/values-lv/strings.xml b/packages/InputDevices/res/values-lv/strings.xml
index 52a0751..881adad 100644
--- a/packages/InputDevices/res/values-lv/strings.xml
+++ b/packages/InputDevices/res/values-lv/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spāņu (latīņu)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latviešu"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persiešu"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaidžāņu"</string>
</resources>
diff --git a/packages/InputDevices/res/values-mk/strings.xml b/packages/InputDevices/res/values-mk/strings.xml
index 2f9befe..49d3d42 100644
--- a/packages/InputDevices/res/values-mk/strings.xml
+++ b/packages/InputDevices/res/values-mk/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"шпански (латиница)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"латвиски"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"персиски"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"азербејџански"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ml/strings.xml b/packages/InputDevices/res/values-ml/strings.xml
index 6b5ed06..dfd9754 100644
--- a/packages/InputDevices/res/values-ml/strings.xml
+++ b/packages/InputDevices/res/values-ml/strings.xml
@@ -42,4 +42,6 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"സ്പാനിഷ് (ലാറ്റിൻ)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"ലാറ്റ്വിയന്"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"പേര്ഷ്യന്"</string>
+ <!-- no translation found for keyboard_layout_azerbaijani (7315895417176467567) -->
+ <skip />
</resources>
diff --git a/packages/InputDevices/res/values-mn/strings.xml b/packages/InputDevices/res/values-mn/strings.xml
index 82e664e..e244722 100644
--- a/packages/InputDevices/res/values-mn/strings.xml
+++ b/packages/InputDevices/res/values-mn/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Испани (Латин)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Латви"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Перс"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Азербайжан"</string>
</resources>
diff --git a/packages/InputDevices/res/values-mr/strings.xml b/packages/InputDevices/res/values-mr/strings.xml
index e8575a8..7189197 100644
--- a/packages/InputDevices/res/values-mr/strings.xml
+++ b/packages/InputDevices/res/values-mr/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"स्पॅनिश (लॅटिन)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"लाट्वियन"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"पर्शियन"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"अझरबैजानी"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ms/strings.xml b/packages/InputDevices/res/values-ms/strings.xml
index 0f402e7..4deafa3 100644
--- a/packages/InputDevices/res/values-ms/strings.xml
+++ b/packages/InputDevices/res/values-ms/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Bahasa Sepanyol (Latin)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Bahasa Latvia"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Bahasa Parsi"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Bahasa Azerbaijan"</string>
</resources>
diff --git a/packages/InputDevices/res/values-my/strings.xml b/packages/InputDevices/res/values-my/strings.xml
index 2467353..b97b6f1 100644
--- a/packages/InputDevices/res/values-my/strings.xml
+++ b/packages/InputDevices/res/values-my/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"စပိန် (လက်တင်)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"လာတ်ဗီယံ"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"ပါရှန်"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"အဇာဘိုင်ဂျန်"</string>
</resources>
diff --git a/packages/InputDevices/res/values-nb/strings.xml b/packages/InputDevices/res/values-nb/strings.xml
index bd2879e..328effa 100644
--- a/packages/InputDevices/res/values-nb/strings.xml
+++ b/packages/InputDevices/res/values-nb/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spansk (latinsk)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvisk"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persisk"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Aserbajdsjansk"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ne/strings.xml b/packages/InputDevices/res/values-ne/strings.xml
index 55969c9..d33cd32 100644
--- a/packages/InputDevices/res/values-ne/strings.xml
+++ b/packages/InputDevices/res/values-ne/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"स्पेनेली(ल्याटिन)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"लातभियन"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"फारसी"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"अजरबैजानी"</string>
</resources>
diff --git a/packages/InputDevices/res/values-nl/strings.xml b/packages/InputDevices/res/values-nl/strings.xml
index e40248f..45a3e52 100644
--- a/packages/InputDevices/res/values-nl/strings.xml
+++ b/packages/InputDevices/res/values-nl/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spaans (Latijns-Amerika)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Lets"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Perzisch"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbeidzjaans"</string>
</resources>
diff --git a/packages/InputDevices/res/values-pa/strings.xml b/packages/InputDevices/res/values-pa/strings.xml
index 951adc8..1cf6a2e 100644
--- a/packages/InputDevices/res/values-pa/strings.xml
+++ b/packages/InputDevices/res/values-pa/strings.xml
@@ -42,4 +42,6 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ਸਪੇਨੀ (ਲਾਤੀਨੀ)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"ਲਾਤਵੀਅਨ"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"ਫ਼ਾਰਸੀ"</string>
+ <!-- no translation found for keyboard_layout_azerbaijani (7315895417176467567) -->
+ <skip />
</resources>
diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml
index a307940..0d4a65b 100644
--- a/packages/InputDevices/res/values-pl/strings.xml
+++ b/packages/InputDevices/res/values-pl/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"hiszpański (Ameryka Łacińska)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"łotewski"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Perski"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerski"</string>
</resources>
diff --git a/packages/InputDevices/res/values-pt-rBR/strings.xml b/packages/InputDevices/res/values-pt-rBR/strings.xml
index ad2abe1..9c01cf0 100644
--- a/packages/InputDevices/res/values-pt-rBR/strings.xml
+++ b/packages/InputDevices/res/values-pt-rBR/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanhol (América Latina)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letão"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persa"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijano"</string>
</resources>
diff --git a/packages/InputDevices/res/values-pt-rPT/strings.xml b/packages/InputDevices/res/values-pt-rPT/strings.xml
index a5beee4..ddc6262 100644
--- a/packages/InputDevices/res/values-pt-rPT/strings.xml
+++ b/packages/InputDevices/res/values-pt-rPT/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanhol (América Latina)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letão"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persa"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azeri"</string>
</resources>
diff --git a/packages/InputDevices/res/values-pt/strings.xml b/packages/InputDevices/res/values-pt/strings.xml
index ad2abe1..9c01cf0 100644
--- a/packages/InputDevices/res/values-pt/strings.xml
+++ b/packages/InputDevices/res/values-pt/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanhol (América Latina)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letão"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persa"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijano"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ro/strings.xml b/packages/InputDevices/res/values-ro/strings.xml
index a933a70..64edffa 100644
--- a/packages/InputDevices/res/values-ro/strings.xml
+++ b/packages/InputDevices/res/values-ro/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spaniolă (America Latină)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letonă"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persană"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azeră"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ru/strings.xml b/packages/InputDevices/res/values-ru/strings.xml
index 127a84d..6e147eb 100644
--- a/packages/InputDevices/res/values-ru/strings.xml
+++ b/packages/InputDevices/res/values-ru/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Испанский (Латинская Америка)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"латышский"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Персидский"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Азербайджанский"</string>
</resources>
diff --git a/packages/InputDevices/res/values-si/strings.xml b/packages/InputDevices/res/values-si/strings.xml
index 8192c18..eda2d97 100644
--- a/packages/InputDevices/res/values-si/strings.xml
+++ b/packages/InputDevices/res/values-si/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ස්පාඤ්ඤය (ලතින්)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"ලැට්වියානු"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"පර්සියානු"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"අසර්බයිජාන"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sk/strings.xml b/packages/InputDevices/res/values-sk/strings.xml
index c631095..101ffff 100644
--- a/packages/InputDevices/res/values-sk/strings.xml
+++ b/packages/InputDevices/res/values-sk/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Španielčina (Latinská Amerika)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Lotyština"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Perzština"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbajdžančina"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sl/strings.xml b/packages/InputDevices/res/values-sl/strings.xml
index c5a19be..4242291 100644
--- a/packages/InputDevices/res/values-sl/strings.xml
+++ b/packages/InputDevices/res/values-sl/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španščina (Latinska Amerika)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"latvijščina"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"perzijščina"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"azerbajdžanščina"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sq/strings.xml b/packages/InputDevices/res/values-sq/strings.xml
index dbc5b4d..5dcfc54 100644
--- a/packages/InputDevices/res/values-sq/strings.xml
+++ b/packages/InputDevices/res/values-sq/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"spanjisht (latine)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"letonisht"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persisht"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbajxhanisht"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sr/strings.xml b/packages/InputDevices/res/values-sr/strings.xml
index 29eea72..abb796f 100644
--- a/packages/InputDevices/res/values-sr/strings.xml
+++ b/packages/InputDevices/res/values-sr/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"шпански (Латинска Америка)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"летонски"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"персијска"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"азербејџанска"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml
index 9954a2b..2961425 100644
--- a/packages/InputDevices/res/values-sv/strings.xml
+++ b/packages/InputDevices/res/values-sv/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanska (latinamerikansk)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"lettiska"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"persiska"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"azerbajdzjanska"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sw/strings.xml b/packages/InputDevices/res/values-sw/strings.xml
index 13b3954..4366204 100644
--- a/packages/InputDevices/res/values-sw/strings.xml
+++ b/packages/InputDevices/res/values-sw/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Kihispania (Kilatini)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Kilatvia"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Kiajemi"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Kiazabaijani"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ta/strings.xml b/packages/InputDevices/res/values-ta/strings.xml
index fec9d8c..ebee5c1 100644
--- a/packages/InputDevices/res/values-ta/strings.xml
+++ b/packages/InputDevices/res/values-ta/strings.xml
@@ -42,4 +42,6 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ஸ்பானிஷ் (லத்தீன்)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"லத்வியன்"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"பெர்சியன்"</string>
+ <!-- no translation found for keyboard_layout_azerbaijani (7315895417176467567) -->
+ <skip />
</resources>
diff --git a/packages/InputDevices/res/values-te/strings.xml b/packages/InputDevices/res/values-te/strings.xml
index 922868d..141bb95 100644
--- a/packages/InputDevices/res/values-te/strings.xml
+++ b/packages/InputDevices/res/values-te/strings.xml
@@ -42,4 +42,6 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"స్పానిష్ (లాటిన్)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"లాత్వియన్"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"పర్షియన్"</string>
+ <!-- no translation found for keyboard_layout_azerbaijani (7315895417176467567) -->
+ <skip />
</resources>
diff --git a/packages/InputDevices/res/values-th/strings.xml b/packages/InputDevices/res/values-th/strings.xml
index 69d9ddf..65085dc 100644
--- a/packages/InputDevices/res/values-th/strings.xml
+++ b/packages/InputDevices/res/values-th/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"สเปน (ละติน)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"ลัตเวีย"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"เปอร์เซีย"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"อาเซอร์ไบจาน"</string>
</resources>
diff --git a/packages/InputDevices/res/values-tl/strings.xml b/packages/InputDevices/res/values-tl/strings.xml
index 4482128..c9fc26d 100644
--- a/packages/InputDevices/res/values-tl/strings.xml
+++ b/packages/InputDevices/res/values-tl/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvian"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persian"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijani"</string>
</resources>
diff --git a/packages/InputDevices/res/values-tr/strings.xml b/packages/InputDevices/res/values-tr/strings.xml
index 08e5e3e..98e6b51 100644
--- a/packages/InputDevices/res/values-tr/strings.xml
+++ b/packages/InputDevices/res/values-tr/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"İspanyolca (Latin)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letonca"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Farsça"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerice"</string>
</resources>
diff --git a/packages/InputDevices/res/values-uk/strings.xml b/packages/InputDevices/res/values-uk/strings.xml
index b81f672..c49ee9e 100644
--- a/packages/InputDevices/res/values-uk/strings.xml
+++ b/packages/InputDevices/res/values-uk/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Іспанська (латиниця)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Латвійська"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Перська"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"азербайджанська"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ur/strings.xml b/packages/InputDevices/res/values-ur/strings.xml
index 2508d5d..71ce1cc 100644
--- a/packages/InputDevices/res/values-ur/strings.xml
+++ b/packages/InputDevices/res/values-ur/strings.xml
@@ -42,4 +42,6 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ہسپانوی (لاطینی)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"لاتویائی"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"فارسی"</string>
+ <!-- no translation found for keyboard_layout_azerbaijani (7315895417176467567) -->
+ <skip />
</resources>
diff --git a/packages/InputDevices/res/values-uz/strings.xml b/packages/InputDevices/res/values-uz/strings.xml
index 4b9d08b..e820469 100644
--- a/packages/InputDevices/res/values-uz/strings.xml
+++ b/packages/InputDevices/res/values-uz/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Ispan (lotin)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latish"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Fors"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"ozarbayjon"</string>
</resources>
diff --git a/packages/InputDevices/res/values-vi/strings.xml b/packages/InputDevices/res/values-vi/strings.xml
index 35c5960..e92d8fc6 100644
--- a/packages/InputDevices/res/values-vi/strings.xml
+++ b/packages/InputDevices/res/values-vi/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Tiếng Tây Ban Nha (La tinh)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Tiếng Latvia"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Tiếng Ba Tư"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Tiếng Azerbaijan"</string>
</resources>
diff --git a/packages/InputDevices/res/values-zh-rCN/strings.xml b/packages/InputDevices/res/values-zh-rCN/strings.xml
index 5f1fc17..61c6bc9 100644
--- a/packages/InputDevices/res/values-zh-rCN/strings.xml
+++ b/packages/InputDevices/res/values-zh-rCN/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"西班牙语(拉丁美洲)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"拉脱维亚语"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"波斯语"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"阿塞拜疆语"</string>
</resources>
diff --git a/packages/InputDevices/res/values-zh-rHK/strings.xml b/packages/InputDevices/res/values-zh-rHK/strings.xml
index 086f966..bf0e2b7 100644
--- a/packages/InputDevices/res/values-zh-rHK/strings.xml
+++ b/packages/InputDevices/res/values-zh-rHK/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"西班牙文 (拉丁美洲)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"拉脫維亞文"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"波斯文"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"亞塞拜疆文"</string>
</resources>
diff --git a/packages/InputDevices/res/values-zh-rTW/strings.xml b/packages/InputDevices/res/values-zh-rTW/strings.xml
index 5e2890f..785cc3d 100644
--- a/packages/InputDevices/res/values-zh-rTW/strings.xml
+++ b/packages/InputDevices/res/values-zh-rTW/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"西班牙文 (拉丁美洲)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"拉脫維亞文"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"波斯文"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"亞塞拜然文"</string>
</resources>
diff --git a/packages/InputDevices/res/values-zu/strings.xml b/packages/InputDevices/res/values-zu/strings.xml
index 18d26a2..1643f01 100644
--- a/packages/InputDevices/res/values-zu/strings.xml
+++ b/packages/InputDevices/res/values-zu/strings.xml
@@ -42,4 +42,5 @@
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Isi-Spanish (Latin)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Isi-Latvian"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Isi-Persian"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Isi-Azebhayijani"</string>
</resources>
diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml
index 1e26226..61d3234 100644
--- a/packages/InputDevices/res/values/strings.xml
+++ b/packages/InputDevices/res/values/strings.xml
@@ -122,4 +122,7 @@
<!-- Persian keyboard layout label. [CHAR LIMIT=35] -->
<string name="keyboard_layout_persian">Persian</string>
+
+ <!-- Azerbaijani keyboard layout label. [CHAR LIMIT=35] -->
+ <string name="keyboard_layout_azerbaijani">Azerbaijani</string>
</resources>
diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml
index c55711a..c6bfc1f 100644
--- a/packages/InputDevices/res/xml/keyboard_layouts.xml
+++ b/packages/InputDevices/res/xml/keyboard_layouts.xml
@@ -155,4 +155,8 @@
<keyboard-layout android:name="keyboard_layout_persian"
android:label="@string/keyboard_layout_persian"
android:keyboardLayout="@raw/keyboard_layout_persian" />
+
+ <keyboard-layout android:name="keyboard_layout_azerbaijani"
+ android:label="@string/keyboard_layout_azerbaijani"
+ android:keyboardLayout="@raw/keyboard_layout_azerbaijani" />
</keyboard-layouts>
diff --git a/packages/MtpDocumentsProvider/tests/Android.mk b/packages/MtpDocumentsProvider/tests/Android.mk
index 148cd0d..ba346f4 100644
--- a/packages/MtpDocumentsProvider/tests/Android.mk
+++ b/packages/MtpDocumentsProvider/tests/Android.mk
@@ -3,8 +3,8 @@
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
+LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_PACKAGE_NAME := MtpDocumentsProviderTests
LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider
LOCAL_CERTIFICATE := media
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/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index eac6d36..5da31bd 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -56,8 +56,8 @@
<string name="print_select_printer" msgid="7388760939873368698">"Selecionar impressora"</string>
<string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
<plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
- <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> impressora encontrada</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> impressora encontrada</item>
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Mais informações acerca desta impressora"</string>
@@ -76,8 +76,8 @@
<string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
<plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
- <item quantity="one">Instale para detetar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
<item quantity="other">Instale para detetar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+ <item quantity="one">Instale para detetar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
</plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"A imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"A cancelar <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/Android.mk b/packages/SettingsLib/Android.mk
index 99f7f71..69287e8 100644
--- a/packages/SettingsLib/Android.mk
+++ b/packages/SettingsLib/Android.mk
@@ -13,13 +13,11 @@
android-support-v7-recyclerview \
android-support-v7-preference \
android-support-v7-appcompat \
- android-support-v14-preference
-
-LOCAL_SHARED_JAVA_LIBRARIES := \
- apptoolkit-lifecycle-common \
+ android-support-v14-preference \
apptoolkit-lifecycle-runtime
-LOCAL_STATIC_JAVA_LIBRARY := legacy-android-test
+LOCAL_SHARED_JAVA_LIBRARIES := \
+ apptoolkit-lifecycle-common
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
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/layout/preference_dropdown_material_settings.xml b/packages/SettingsLib/res/layout/preference_dropdown_material_settings.xml
new file mode 100644
index 0000000..a0b8155
--- /dev/null
+++ b/packages/SettingsLib/res/layout/preference_dropdown_material_settings.xml
@@ -0,0 +1,35 @@
+<?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.
+ -->
+
+
+<!-- Based off frameworks/base/core/res/res/layout/preference_dropdown_material.xml
+ except that icon space in this layout is always reserved -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <Spinner
+ android:id="@+id/spinner"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/preference_no_icon_padding_start"
+ android:visibility="invisible" />
+
+ <include layout="@layout/preference_material"/>
+
+</FrameLayout>
\ No newline at end of file
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-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 75a0a42..a5c2e41 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/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-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..d12ac8a 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>
@@ -121,8 +128,8 @@
<string name="running_process_item_user_label" msgid="3129887865552025943">"Nutzer: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="313159469856372621">"Einige Standardeinstellungen festgelegt"</string>
<string name="launch_defaults_none" msgid="4241129108140034876">"Keine Standardeinstellungen festgelegt"</string>
- <string name="tts_settings" msgid="8186971894801348327">"Text-in-Sprache"</string>
- <string name="tts_settings_title" msgid="1237820681016639683">"Text-in-Sprache-Ausgabe"</string>
+ <string name="tts_settings" msgid="8186971894801348327">"Sprachausgabe"</string>
+ <string name="tts_settings_title" msgid="1237820681016639683">"Sprachausgabe-Ausgabe"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Sprechgeschwindigkeit"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Geschwindigkeit, mit der der Text gesprochen wird"</string>
<string name="tts_default_pitch_title" msgid="6135942113172488671">"Tonlage"</string>
@@ -136,7 +143,7 @@
<string name="tts_install_data_title" msgid="4264378440508149986">"Sprachdaten installieren"</string>
<string name="tts_install_data_summary" msgid="5742135732511822589">"Sprachdaten für Sprachsynthese installieren"</string>
<string name="tts_engine_security_warning" msgid="8786238102020223650">"Dieses Sprachsynthesemodul kann den gesamten gesprochenen Text erfassen, einschließlich personenbezogener Daten wie Passwörter und Kreditkartennummern. Es ist Teil der App \"<xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>\". Möchtest du dieses Sprachsynthesemodul aktivieren?"</string>
- <string name="tts_engine_network_required" msgid="1190837151485314743">"Für diese Sprache ist zur Text-in-Sprache-Ausgabe eine aktive Netzwerkverbindung erforderlich."</string>
+ <string name="tts_engine_network_required" msgid="1190837151485314743">"Für diese Sprache ist zur Sprachausgabe-Ausgabe eine aktive Netzwerkverbindung erforderlich."</string>
<string name="tts_default_sample_string" msgid="4040835213373086322">"Dies ist ein Beispiel für Sprachsynthese."</string>
<string name="tts_status_title" msgid="7268566550242584413">"Status der Standardsprache"</string>
<string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> wird vollständig unterstützt."</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..fcca957 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -33,16 +33,14 @@
<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_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"एक्सेस पॉइंट फ़िलहाल भरा हुआ है"</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>
<string name="speed_label_very_slow" msgid="1867055264243608530">"अत्यधिक धीमी"</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>
@@ -179,7 +176,7 @@
<string name="development_settings_not_available" msgid="4308569041701535607">"यह उपयोगकर्ता, डेवलपर के लिए सेटिंग और टूल का इस्तेमाल नहीं कर सकता"</string>
<string name="vpn_settings_not_available" msgid="956841430176985598">"VPN सेटिंग इस उपयोगकर्ता के लिए उपलब्ध नहीं हैं"</string>
<string name="tethering_settings_not_available" msgid="6765770438438291012">"टेदरिंग सेटिंग इस उपयोगकर्ता के लिए उपलब्ध नहीं हैं"</string>
- <string name="apn_settings_not_available" msgid="7873729032165324000">"एक्सेस पॉइंट नाम सेटिंग इस उपयोगकर्ता के लिए मौजूद नहीं हैं"</string>
+ <string name="apn_settings_not_available" msgid="7873729032165324000">"एक्सेस प्वाइंट नाम सेटिंग इस उपयोगकर्ता के लिए मौजूद नहीं हैं"</string>
<string name="enable_adb" msgid="7982306934419797485">"USB डीबग करना"</string>
<string name="enable_adb_summary" msgid="4881186971746056635">"डीबग मोड जब USB कनेक्ट किया गया हो"</string>
<string name="clear_adb_keys" msgid="4038889221503122743">"USB डीबग करने की मंज़ूरी रद्द करें"</string>
@@ -204,7 +201,7 @@
<string name="mobile_data_always_on" msgid="8774857027458200434">"मोबाइल डेटा हमेशा सक्रिय"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"हार्डवेयर से तेज़ी लाने के लिए टेदर करें"</string>
<string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"बिना नाम वाले ब्लूटूथ डिवाइस दिखाएं"</string>
- <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"पूर्ण वॉल्यूम अक्षम करें"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ब्लूटूथ से आवाज़ के नियंत्रण की सुविधा रोकें"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"इन-बैंड रिंग करना चालू करें"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ब्लूटूथ AVRCP वर्शन"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"ब्लूटूथ AVRCP वर्शन चुनें"</string>
@@ -250,7 +247,7 @@
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB पर ऐप की पुष्टि करें"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"नुकसानदेह व्यवहार के लिए ADB/ADT के द्वारा इंस्टॉल किए गए ऐप्स जाँचें."</string>
<string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"बिना नाम वाले ब्लूटूथ डिवाइस (केवल MAC पते वाले) दिखाए जाएंगे"</string>
- <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"दूरस्थ डिवाइस के साथ वॉल्यूम की समस्याओं जैसे अस्वीकार्य तेज़ वॉल्यूम या नियंत्रण की कमी की स्थिति में ब्लूटूथ पूर्ण वॉल्यूम सुविधा को अक्षम करता है."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"दूर के डिवाइस पर आवाज़ बहुत बढ़ जाने या उससे नियंत्रण हटने जैसी समस्याएं होने पर, यह ब्लूटूथ के ज़रिए आवाज़ के नियंत्रण की सुविधा रोक देता है."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"फ़ोन की रिंगटोन को ब्लूटूथ हेडसेट पर बजने दें"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"स्थानीय टर्मिनल"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"लोकल शेल तक पहुंचने की सुविधा देने वाले टर्मिनल ऐप को चालू करें"</string>
@@ -320,8 +317,8 @@
<string name="enable_freeform_support" msgid="1461893351278940416">"फ़्रीफ़ॉर्म विंडो (एक साथ कई विंडो दिखाना) चालू करें"</string>
<string name="enable_freeform_support_summary" msgid="8247310463288834487">"जाँच के लिए बनी फ़्रीफ़ॉर्म विंडो के लिए सहायता चालू करें."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटॉप बैकअप पासवर्ड"</string>
- <string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटॉप पूर्ण बैकअप वर्तमान में सुरक्षित नहीं हैं"</string>
- <string name="local_backup_password_summary_change" msgid="5376206246809190364">"डेस्कटॉप के पूर्ण बैकअप का पासवर्ड बदलने या निकालने के लिए टैप करें"</string>
+ <string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटॉप के पूरे बैक अप फ़िलहाल सुरक्षित नहीं हैं"</string>
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"डेस्कटॉप के पूरे बैक अप का पासवर्ड बदलने या हटाने के लिए टैप करें"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"नया बैकअप पासवर्ड सेट किया गया"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"नया पासवर्ड तथा पुष्टि मेल नही खाते"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"सुरक्षित पासवर्ड सेट करने में विफल रहा"</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/values/styles_support_preference.xml b/packages/SettingsLib/res/values/styles_support_preference.xml
index d7032b8..cf9f3c6 100644
--- a/packages/SettingsLib/res/values/styles_support_preference.xml
+++ b/packages/SettingsLib/res/values/styles_support_preference.xml
@@ -20,14 +20,73 @@
<dimen name="preference_no_icon_padding_start">72dp</dimen>
+ <!-- Fragment style -->
+ <style name="PreferenceFragmentStyle.SettingsBase" parent="@*android:style/PreferenceFragment.Material">
+ <item name="allowDividerAfterLastItem">false</item>
+ </style>
+
+ <!-- Preferences -->
+ <style name="Preference.SettingsBase" parent="@style/Preference.Material">
+ <item name="allowDividerAbove">false</item>
+ <item name="allowDividerBelow">true</item>
+ <item name="singleLineTitle">false</item>
+ <item name="iconSpaceReserved">true</item>
+ </style>
+
+ <!-- Preference category -->
+ <style name="Preference.Category.SettingsBase" parent="@style/Preference.Category.Material">
+ <item name="allowDividerAbove">true</item>
+ <item name="allowDividerBelow">true</item>
+ <item name="android:layout">@layout/preference_category_material_settings</item>
+ </style>
+
+ <!-- Preference screen -->
+ <style name="Preference.Screen.SettingsBase" parent="@style/Preference.PreferenceScreen.Material">
+ <item name="allowDividerAbove">false</item>
+ <item name="allowDividerBelow">true</item>
+ <item name="iconSpaceReserved">true</item>
+ </style>
+
<!-- Footer Preferences -->
- <style name="Preference.FooterPreference.SettingsBase" parent="@style/Preference.Material">
+ <style name="Preference.FooterPreference.SettingsBase" parent="Preference.SettingsBase">
<item name="android:layout">@layout/preference_footer</item>
<item name="allowDividerAbove">true</item>
</style>
+ <!-- Dropdown Preferences -->
+ <style name="Preference.DropdownPreference.SettingsBase" parent="Preference.SettingsBase">
+ <item name="android:layout">@layout/preference_dropdown_material_settings</item>
+ </style>
+
+ <!-- Switch Preferences -->
+ <style name="Preference.SwitchPreference.SettingsBase" parent="@style/Preference.SwitchPreference.Material">
+ <item name="allowDividerAbove">false</item>
+ <item name="allowDividerBelow">true</item>
+ <item name="iconSpaceReserved">true</item>
+ <item name="singleLineTitle">false</item>
+ </style>
+
+ <!-- EditText Preferences -->
+ <style name="Preference.EditTextPreference.SettingsBase"
+ parent="@style/Preference.DialogPreference.EditTextPreference.Material">
+ <item name="allowDividerAbove">false</item>
+ <item name="allowDividerBelow">true</item>
+ <item name="iconSpaceReserved">true</item>
+ <item name="singleLineTitle">false</item>
+ </style>
+
<style name="PreferenceThemeOverlay.SettingsBase" parent="@style/PreferenceThemeOverlay.v14.Material">
+ <!-- Parent path frameworks/support/v14/preference/res/values/themes.xml -->
+ <item name="android:scrollbars">vertical</item>
+ <item name="preferenceFragmentStyle">@style/PreferenceFragmentStyle.SettingsBase</item>
+ <item name="preferenceCategoryStyle">@style/Preference.Category.SettingsBase</item>
+ <item name="preferenceScreenStyle">@style/Preference.Screen.SettingsBase</item>
+ <item name="preferenceStyle">@style/Preference.SettingsBase</item>
+ <item name="dialogPreferenceStyle">@style/Preference.SettingsBase</item>
+ <item name="editTextPreferenceStyle">@style/Preference.EditTextPreference.SettingsBase</item>
<item name="footerPreferenceStyle">@style/Preference.FooterPreference.SettingsBase</item>
+ <item name="switchPreferenceStyle">@style/Preference.SwitchPreference.SettingsBase</item>
+ <item name="dropdownPreferenceStyle">@style/Preference.DropdownPreference.SettingsBase</item>
</style>
</resources>
\ No newline at end of file
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 eb33842..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.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 2873fb6..9caff10 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -135,7 +135,8 @@
if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
if (profile instanceof MapProfile) {
profile.setPreferred(mDevice, true);
- } else if (!mProfiles.contains(profile)) {
+ }
+ if (!mProfiles.contains(profile)) {
mRemovedProfiles.remove(profile);
mProfiles.add(profile);
if (profile instanceof PanProfile &&
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/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
old mode 100755
new mode 100644
index 9cda669..991d922
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -25,6 +25,7 @@
import android.bluetooth.BluetoothMap;
import android.bluetooth.BluetoothMapClient;
import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothPbap;
import android.bluetooth.BluetoothPbapClient;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
@@ -140,9 +141,11 @@
BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
}
- //Create PBAP server profile, but do not add it to list of profiles
- // as we do not need to monitor the profile as part of profile list
+ //Create PBAP server profile
+ if(DEBUG) Log.d(TAG, "Adding local PBAP profile");
mPbapProfile = new PbapServerProfile(context);
+ addProfile(mPbapProfile, PbapServerProfile.NAME,
+ BluetoothPbap.ACTION_CONNECTION_STATE_CHANGED);
if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete");
}
@@ -495,6 +498,13 @@
mMapProfile.setPreferred(device, true);
}
+ if ((mPbapProfile != null) &&
+ (mPbapProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
+ profiles.add(mPbapProfile);
+ removedProfiles.remove(mPbapProfile);
+ mPbapProfile.setPreferred(device, true);
+ }
+
if (mMapClientProfile != null) {
profiles.add(mMapClientProfile);
removedProfiles.remove(mMapClientProfile);
@@ -503,8 +513,6 @@
if (mUsePbapPce) {
profiles.add(mPbapClientProfile);
removedProfiles.remove(mPbapClientProfile);
- profiles.remove(mPbapProfile);
- removedProfiles.add(mPbapProfile);
}
if (DEBUG) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index f3b6912..58465f2 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -91,7 +91,7 @@
public boolean disconnect(BluetoothDevice device) {
if (mService == null) return false;
- return mService.disconnect();
+ return mService.disconnect(device);
}
public int getConnectionStatus(BluetoothDevice device) {
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/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..cfb3519d 100644
--- a/packages/SettingsLib/tests/integ/Android.mk
+++ b/packages/SettingsLib/tests/integ/Android.mk
@@ -20,18 +20,19 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
+LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.test.base
LOCAL_JACK_FLAGS := --multi-dex native
LOCAL_PACKAGE_NAME := SettingsLibTests
LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_USE_AAPT2 := true
+
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
espresso-core \
mockito-target-minus-junit4 \
- legacy-android-test \
truth-prebuilt
# Code coverage puts us over the dex limit, so enable multi-dex for coverage-enabled builds
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..e840a4b 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
@@ -45,9 +45,9 @@
import android.view.inputmethod.InputMethodInfo;
import com.android.settingslib.BaseTest;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.compat.ArgumentMatcher;
import java.util.ArrayList;
import java.util.List;
@@ -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);
}
@@ -241,7 +241,7 @@
return ri;
}
- private class IntentMatcher extends ArgumentMatcher<Intent> {
+ private class IntentMatcher implements ArgumentMatcher<Intent> {
private final Intent mIntent;
IntentMatcher(Intent intent) {
@@ -249,11 +249,8 @@
}
@Override
- public boolean matchesObject(Object argument) {
- if (argument instanceof Intent) {
- return ((Intent) argument).filterEquals(mIntent);
- }
- return false;
+ public boolean matches(Intent argument) {
+ return argument != null && argument.filterEquals(mIntent);
}
@Override
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 4a1d392..e64fc75 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -767,10 +767,12 @@
WifiTracker tracker = createMockedWifiTracker();
startTracking(tracker);
+ CountDownLatch ready = new CountDownLatch(1);
CountDownLatch latch = new CountDownLatch(1);
CountDownLatch lock = new CountDownLatch(1);
tracker.mMainHandler.post(() -> {
try {
+ ready.countDown();
lock.await();
latch.countDown();
} catch (InterruptedException e) {
@@ -786,6 +788,9 @@
tracker.mMainHandler.sendEmptyMessage(
WifiTracker.MainHandler.MSG_WIFI_STATE_CHANGED);
+ try {
+ ready.await(); // Make sure we have entered the first message handler
+ } catch (InterruptedException e) {}
tracker.onStop();
verify(mockWifiListener, atMost(1)).onAccessPointsChanged();
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/Android.mk b/packages/SettingsProvider/Android.mk
index 069e83a..0f2c5ab 100644
--- a/packages/SettingsProvider/Android.mk
+++ b/packages/SettingsProvider/Android.mk
@@ -7,7 +7,7 @@
src/com/android/providers/settings/EventLogTags.logtags
LOCAL_JAVA_LIBRARIES := telephony-common ims-common
-LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
+LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_PACKAGE_NAME := SettingsProvider
LOCAL_CERTIFICATE := platform
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index 9374d52..287a888 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -11,6 +11,8 @@
android:icon="@mipmap/ic_launcher_settings"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true">
+ <uses-library android:name="android.test.runner" />
+
<provider android:name="SettingsProvider"
android:authorities="settings"
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 52b4f4d..1d3f26ee 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -881,6 +881,9 @@
dumpSetting(s, p,
Settings.Global.GPU_DEBUG_LAYERS,
GlobalSettingsProto.GPU_DEBUG_LAYERS);
+ dumpSetting(s, p,
+ Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
+ GlobalSettingsProto.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING);
// Settings.Global.SHOW_PROCESSES intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Global.LOW_POWER_MODE,
@@ -1057,9 +1060,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/Shell/tests/Android.mk b/packages/Shell/tests/Android.mk
index 48b757c..7f24a38 100644
--- a/packages/Shell/tests/Android.mk
+++ b/packages/Shell/tests/Android.mk
@@ -6,14 +6,13 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
mockito-target-minus-junit4 \
ub-uiautomator \
junit \
- legacy-android-test \
LOCAL_PACKAGE_NAME := ShellTests
LOCAL_COMPATIBILITY_SUITE := device-tests
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..bf0d679 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>
@@ -136,4 +135,12 @@
<item quantity="one">Toestel is <xliff:g id="NUMBER_0">%d</xliff:g> uur lank nie ontsluit nie. Bevestig wagwoord.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Nie herken nie"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Voer SIM-PIN in; jy het <xliff:g id="NUMBER_1">%d</xliff:g> pogings oor.</item>
+ <item quantity="one">Verkeerde SIM-PIN. Jy het <xliff:g id="NUMBER_0">%d</xliff:g> poging oor voordat jy jou diensverskaffer moet kontak om jou toestel te ontsluit.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM is nou gedeaktiveer. Voer PUK-kode in om voort te gaan. Jy het <xliff:g id="_NUMBER_1">%d</xliff:g> pogings oor voordat die SIM permanent onbruikbaar word. Kontak die diensverskaffer vir besonderhede.</item>
+ <item quantity="one">SIM is nou gedeaktiveer. Voer PUK-kode in om voort te gaan. Jy het <xliff:g id="_NUMBER_0">%d</xliff:g> poging oor voordat die SIM permanent onbruikbaar word. Kontak die diensverskaffer vir besonderhede.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index 8fb0539..340e514 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>
@@ -136,4 +135,12 @@
<item quantity="other">መሣሪያው ለ<xliff:g id="NUMBER_1">%d</xliff:g> ሰዓቶች አልተከፈተም ነበር። የይለፍ ቃል ያረጋግጡ።</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"አልታወቀም"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <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>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">ሲም አሁን ተሰናክሏል። ለመቀጠል የPUK ኮድ ያስገቡ። ሲም እስከመጨረሻው መጠቀም የማይቻል ከመሆኑ በፊት <xliff:g id="_NUMBER_1">%d</xliff:g> ሙከራዎች ይቀረዎታል። ዝርዝሮችን ለማግኘት የአገልግሎት አቅራቢን ያነጋግሩ።</item>
+ <item quantity="other">ሲም አሁን ተሰናክሏል። ለመቀጠል የPUK ኮድ ያስገቡ። ሲም እስከመጨረሻው መጠቀም የማይቻል ከመሆኑ በፊት <xliff:g id="_NUMBER_1">%d</xliff:g> ሙከራዎች ይቀረዎታል። ዝርዝሮችን ለማግኘት የአገልግሎት አቅራቢን ያነጋግሩ።</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index 839fb87..7027d6f 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -159,4 +159,20 @@
<item quantity="one">لم يتم إلغاء تأمين الجهاز لمدة <xliff:g id="NUMBER_0">%d</xliff:g> ساعة. تأكيد كلمة المرور.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"لم يتم التعرف عليها"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="zero">أدخل رقم التعريف الشخصي لشريحة SIM، وتتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولات.</item>
+ <item quantity="two">أدخل رقم التعريف الشخصي لشريحة SIM، وتتبقى لديك محاولتان (<xliff:g id="NUMBER_1">%d</xliff:g>).</item>
+ <item quantity="few">أدخل رقم التعريف الشخصي لشريحة SIM، وتتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولات.</item>
+ <item quantity="many">أدخل رقم التعريف الشخصي لشريحة SIM، وتتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولة.</item>
+ <item quantity="other">أدخل رقم التعريف الشخصي لشريحة SIM، وتتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولة.</item>
+ <item quantity="one">أدخل رقم التعريف الشخصي لشريحة SIM، وتتبقى لديك محاولة واحدة (<xliff:g id="NUMBER_0">%d</xliff:g>) يجب أن تتصل بعدها بمشغّل شبكة الجوّال لإلغاء قفل الجهاز.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="zero">تم إيقاف شريحة SIM الآن. أدخل رمز PUK للمتابعة، وتتبقى لديك <xliff:g id="_NUMBER_1">%d</xliff:g> محاولة قبل أن تصبح شريحة SIM غير صالحة للاستخدام نهائيًا. ويمكنك الاتصال بمشغل شبكة الجوّال لمعرفة التفاصيل.</item>
+ <item quantity="two">تم إيقاف شريحة SIM الآن. أدخل رمز PUK للمتابعة، وتتبقى لديك محاولتان (<xliff:g id="_NUMBER_1">%d</xliff:g>) قبل أن تصبح شريحة SIM غير صالحة للاستخدام نهائيًا. ويمكنك الاتصال بمشغل شبكة الجوّال لمعرفة التفاصيل.</item>
+ <item quantity="few">تم إيقاف شريحة SIM الآن. أدخل رمز PUK للمتابعة، وتتبقى لديك <xliff:g id="_NUMBER_1">%d</xliff:g> محاولات قبل أن تصبح شريحة SIM غير صالحة للاستخدام نهائيًا. ويمكنك الاتصال بمشغل شبكة الجوّال لمعرفة التفاصيل.</item>
+ <item quantity="many">تم إيقاف شريحة SIM الآن. أدخل رمز PUK للمتابعة، وتتبقى لديك <xliff:g id="_NUMBER_1">%d</xliff:g> محاولة قبل أن تصبح شريحة SIM غير صالحة للاستخدام نهائيًا. ويمكنك الاتصال بمشغل شبكة الجوّال لمعرفة التفاصيل.</item>
+ <item quantity="other">تم إيقاف شريحة SIM الآن. أدخل رمز PUK للمتابعة، وتتبقى لديك <xliff:g id="_NUMBER_1">%d</xliff:g> محاولة قبل أن تصبح شريحة SIM غير صالحة للاستخدام نهائيًا. ويمكنك الاتصال بمشغل شبكة الجوّال لمعرفة التفاصيل.</item>
+ <item quantity="one">تم إيقاف شريحة SIM الآن. أدخل رمز PUK للمتابعة، وتتبقى لديك محاولة واحدة (<xliff:g id="_NUMBER_0">%d</xliff:g>) قبل أن تصبح شريحة SIM غير صالحة للاستخدام نهائيًا. ويمكنك الاتصال بمشغل شبكة الجوّال لمعرفة التفاصيل.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index ab0e8ea..b0503ea 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>
@@ -136,4 +135,12 @@
<item quantity="one">Cihaz <xliff:g id="NUMBER_0">%d</xliff:g> saat kiliddən çıxarılmayıb. Parolu təsdiq edin.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Tanınmır"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">SIM PIN-ni daxil edin, <xliff:g id="NUMBER_1">%d</xliff:g> cəhdiniz qalır.</item>
+ <item quantity="one">Yanlış SIM PIN kodu, cihazınızı kiliddən çıxarmaq üçün operatorunuzla əlaqə saxlamadan öncə <xliff:g id="NUMBER_0">%d</xliff:g> cəhdiniz qalır.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM indi deaktivdir. Davam etmək üçün PUK kodunu daxil edin. SIM birdəfəlik yararsız olmadan öncə <xliff:g id="_NUMBER_1">%d</xliff:g> cəhdiniz qalır. Ətraflı məlumat üçün operatorla əlaqə saxlayın.</item>
+ <item quantity="one">SIM indi deaktivdir. Davam etmək üçün PUK kodunu daxil edin. SIM birdəfəlik yararsız olmadan öncə <xliff:g id="_NUMBER_0">%d</xliff:g> cəhdiniz qalır. Ətraflı məlumat üçün operatorla əlaqə saxlayın.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
index e24001c..079ba92 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -141,4 +141,14 @@
<item quantity="other">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sati. Potvrdite lozinku.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Nije prepoznat"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Unesite PIN za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
+ <item quantity="few">Unesite PIN za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
+ <item quantity="other">Unesite PIN za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaj pre nego što SIM postane trajno neupotrebljiv. Detaljne informacije potražite od mobilnog operatera.</item>
+ <item quantity="few">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja pre nego što SIM postane trajno neupotrebljiv. Detaljne informacije potražite od mobilnog operatera.</item>
+ <item quantity="other">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja pre nego što SIM postane trajno neupotrebljiv. Detaljne informacije potražite od mobilnog operatera.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index 359271d..a3a381549 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -147,4 +147,16 @@
<item quantity="other">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзіны. Увядзіце пароль.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Не распазнаны"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Увядзіце PIN-код SIM-карты. У вас ёсць яшчэ <xliff:g id="NUMBER_1">%d</xliff:g> спроба.</item>
+ <item quantity="few">Увядзіце PIN-код SIM-карты. У вас ёсць яшчэ <xliff:g id="NUMBER_1">%d</xliff:g> спробы.</item>
+ <item quantity="many">Увядзіце PIN-код SIM-карты. У вас ёсць яшчэ <xliff:g id="NUMBER_1">%d</xliff:g> спроб.</item>
+ <item quantity="other">Увядзіце PIN-код SIM-карты. У вас ёсць яшчэ <xliff:g id="NUMBER_1">%d</xliff:g> спробы.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">SIM-карта заблакіравана. Каб працягнуць, увядзіце PUK-код. У вас ёсць яшчэ <xliff:g id="_NUMBER_1">%d</xliff:g> спроба, пасля чаго SIM-карта будзе заблакіравана назаўсёды. Звярніцеся да аператара, каб даведацца больш.</item>
+ <item quantity="few">SIM-карта заблакіравана. Каб працягнуць, увядзіце PUK-код. У вас ёсць яшчэ <xliff:g id="_NUMBER_1">%d</xliff:g> спробы, пасля чаго SIM-карта будзе заблакіравана назаўсёды. Звярніцеся да аператара, каб даведацца больш.</item>
+ <item quantity="many">SIM-карта заблакіравана. Каб працягнуць, увядзіце PUK-код. У вас ёсць яшчэ <xliff:g id="_NUMBER_1">%d</xliff:g> спроб, пасля чаго SIM-карта будзе заблакіравана назаўсёды. Звярніцеся да аператара, каб даведацца больш.</item>
+ <item quantity="other">SIM-карта заблакіравана. Каб працягнуць, увядзіце PUK-код. У вас ёсць яшчэ <xliff:g id="_NUMBER_1">%d</xliff:g> спробы, пасля чаго SIM-карта будзе заблакіравана назаўсёды. Звярніцеся да аператара, каб даведацца больш.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml
index 8dbdd5c..87c7519 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>
@@ -136,4 +135,12 @@
<item quantity="one">Устройството не е отключвано от <xliff:g id="NUMBER_0">%d</xliff:g> час. Потвърдете паролата.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Не е разпознато"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Въведете ПИН кода за SIM картата – остават ви <xliff:g id="NUMBER_1">%d</xliff:g> опита.</item>
+ <item quantity="one">Въведете ПИН кода за SIM картата – остава ви <xliff:g id="NUMBER_0">%d</xliff:g> опит, преди да трябва да се свържете с оператора си, за да отключите устройството.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM картата вече е деактивирана. Въведете PUK кода, за да продължите. Остават ви <xliff:g id="_NUMBER_1">%d</xliff:g> опита, преди SIM картата да стане неизползваема завинаги. Свържете се с оператора за подробности.</item>
+ <item quantity="one">SIM картата вече е деактивирана. Въведете PUK кода, за да продължите. Остава ви <xliff:g id="_NUMBER_0">%d</xliff:g> опит, преди SIM картата да стане неизползваема завинаги. Свържете се с оператора за подробности.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 22e67b8..5df3989 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -135,4 +135,6 @@
<item quantity="other">ডিভাইসটি <xliff:g id="NUMBER_1">%d</xliff:g> ঘন্টা ধরে আনলক করা হয় নি। পাসওয়ার্ড নিশ্চিত করুন।</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"স্বীকৃত নয়"</string>
+ <!-- no translation found for kg_password_default_pin_message (6203676909479972943) -->
+ <!-- no translation found for kg_password_default_puk_message (8744416410184198352) -->
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index 52712287..b74a618 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -141,4 +141,14 @@
<item quantity="other">Uređaj nije otključavan <xliff:g id="NUMBER_1">%d</xliff:g> sati. Potvrdite lozinku.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Nije prepoznat"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Unesite PIN kôd za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
+ <item quantity="few">Unesite PIN kôd za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
+ <item quantity="other">Unesite PIN kôd za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">SIM kartica je onemogućena. Unesite PUK kôd da nastavite. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaj prije nego što SIM kartica postane trajno neupotrebljiva. Obratite se operateru za više informacija.</item>
+ <item quantity="few">SIM kartica je onemogućena. Unesite PUK kôd da nastavite. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Obratite se operateru za više informacija.</item>
+ <item quantity="other">SIM kartica je onemogućena. Unesite PUK kôd da nastavite. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Obratite se operateru za više informacija.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index 9aa8229..dd2844a 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -135,4 +135,12 @@
<item quantity="one">Fa <xliff:g id="NUMBER_0">%d</xliff:g> hora que no es desbloqueja el dispositiu. Confirma la contrasenya.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"No s\'ha reconegut"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Introdueix el PIN de la SIM. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents.</item>
+ <item quantity="one">Introdueix el PIN de la SIM. Et queda <xliff:g id="NUMBER_0">%d</xliff:g> intent; si no l\'encertes, contacta amb l\'operador de telefonia mòbil per desbloquejar el dispositiu.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">La targeta SIM s\'ha desactivat. Introdueix el codi PUK per continuar. Et queden <xliff:g id="_NUMBER_1">%d</xliff:g> intents; si no l\'encertes, la SIM no es podrà tornar a fer servir. Contacta amb l\'operador de telefonia mòbil per obtenir-ne més informació.</item>
+ <item quantity="one">La targeta SIM s\'ha desactivat. Introdueix el codi PUK per continuar. Et queda <xliff:g id="_NUMBER_0">%d</xliff:g> intent; si no l\'encertes, la SIM no es podrà tornar a fer servir. Contacta amb l\'operador de telefonia mòbil per obtenir-ne més informació.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index 0665ac0..cf7abf1 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>
@@ -148,4 +147,16 @@
<item quantity="one">Zařízení již <xliff:g id="NUMBER_0">%d</xliff:g> hodinu nebylo odemknuto. Zadejte heslo.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Nerozpoznáno"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="few">Zadejte PIN SIM karty. Zbývají <xliff:g id="NUMBER_1">%d</xliff:g> pokusy.</item>
+ <item quantity="many">Zadejte PIN SIM karty. Zbývá <xliff:g id="NUMBER_1">%d</xliff:g> pokusu.</item>
+ <item quantity="other">Zadejte PIN SIM karty. Zbývá <xliff:g id="NUMBER_1">%d</xliff:g> pokusů.</item>
+ <item quantity="one">Zadejte PIN SIM karty. Zbývá <xliff:g id="NUMBER_0">%d</xliff:g> pokus, poté bude muset zařízení odemknout operátor.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="few">SIM karta je nyní zablokována. Chcete-li pokračovat, zadejte kód PUK. Máte ještě <xliff:g id="_NUMBER_1">%d</xliff:g> pokusy, poté bude SIM karta natrvalo zablokována. Podrobnosti vám poskytne operátor.</item>
+ <item quantity="many">SIM karta je nyní zablokována. Chcete-li pokračovat, zadejte kód PUK. Máte ještě <xliff:g id="_NUMBER_1">%d</xliff:g> pokusu, poté bude SIM karta natrvalo zablokována. Podrobnosti vám poskytne operátor.</item>
+ <item quantity="other">SIM karta je nyní zablokována. Chcete-li pokračovat, zadejte kód PUK. Máte ještě <xliff:g id="_NUMBER_1">%d</xliff:g> pokusů, poté bude SIM karta natrvalo zablokována. Podrobnosti vám poskytne operátor.</item>
+ <item quantity="one">SIM karta je nyní zablokována. Chcete-li pokračovat, zadejte kód PUK. Máte ještě <xliff:g id="_NUMBER_0">%d</xliff:g> pokus, poté bude SIM karta natrvalo zablokována. Podrobnosti vám poskytne operátor.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index 354aa96..156da2e 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>
@@ -136,4 +135,12 @@
<item quantity="other">Enheden blev sidst låst op for <xliff:g id="NUMBER_1">%d</xliff:g> timer siden. Bekræft adgangskoden.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Ikke genkendt"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Indtast pinkoden til SIM-kortet. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøg tilbage.</item>
+ <item quantity="other">Indtast pinkoden til SIM-kortet. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøg tilbage.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">SIM-kortet er nu deaktiveret. Indtast PUK-koden for at fortsætte. Du har <xliff:g id="_NUMBER_1">%d</xliff:g> forsøg tilbage, før SIM-kortet bliver permanent ubrugeligt. Kontakt dit mobilselskab for at få flere oplysninger.</item>
+ <item quantity="other">SIM-kortet er nu deaktiveret. Indtast PUK-koden for at fortsætte. Du har <xliff:g id="_NUMBER_1">%d</xliff:g> forsøg tilbage, før SIM-kortet bliver permanent ubrugeligt. Kontakt dit mobilselskab for at få flere oplysninger.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index 9a5ad0e..852a9c1 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>
@@ -136,4 +135,12 @@
<item quantity="one">Das Gerät wurde seit <xliff:g id="NUMBER_0">%d</xliff:g> Stunde nicht mehr entsperrt. Bitte bestätige das Passwort.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Nicht erkannt"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Gib die PIN für die SIM-Karte ein. Du hast noch <xliff:g id="NUMBER_1">%d</xliff:g> Versuche.</item>
+ <item quantity="one">Gib die PIN für die SIM-Karte ein. Du hast noch <xliff:g id="NUMBER_0">%d</xliff:g> Versuch, bevor das Gerät vom Mobilfunkanbieter entsperrt werden muss.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">Die SIM-Karte ist jetzt deaktiviert. Gib den PUK-Code ein, um fortzufahren. Du hast noch <xliff:g id="_NUMBER_1">%d</xliff:g> Versuche, bevor die SIM-Karte endgültig gesperrt wird. Weitere Informationen erhältst du von deinem Mobilfunkanbieter.</item>
+ <item quantity="one">Die SIM-Karte ist jetzt deaktiviert. Gib den PUK-Code ein, um fortzufahren. Du hast noch <xliff:g id="_NUMBER_0">%d</xliff:g> Versuch, bevor die SIM-Karte endgültig gesperrt wird. Weitere Informationen erhältst du von deinem Mobilfunkanbieter.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index 6ec3e57..0127ef1 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>
@@ -136,4 +135,12 @@
<item quantity="one">Η συσκευή δεν έχει ξεκλειδωθεί εδώ και <xliff:g id="NUMBER_0">%d</xliff:g> ώρα. Επιβεβαιώστε τον κωδικό πρόσβασης.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Δεν αναγνωρίστηκε"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Καταχωρίστε τον αριθμό PIN της κάρτας SIM. Απομένουν <xliff:g id="NUMBER_1">%d</xliff:g> ακόμη προσπάθειες.</item>
+ <item quantity="one">Εσφαλμένος αριθμός PIN κάρτας SIM. Απομένει άλλη <xliff:g id="NUMBER_0">%d</xliff:g> προσπάθεια. Στη συνέχεια, θα πρέπει να επικοινωνήσετε με τον πάροχο κινητής τηλεφωνίας, για να ξεκλειδώσετε τη συσκευή.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">Η κάρτα SIM απενεργοποιήθηκε. Καταχωρίστε τον κωδικό PUK, για να συνεχίσετε. Απομένουν <xliff:g id="_NUMBER_1">%d</xliff:g> ακόμη προσπάθειες προτού να μην είναι πλέον δυνατή η χρήση της κάρτας SIM. Επικοινωνήστε με την εταιρεία κινητής τηλεφωνίας για λεπτομέρειες.</item>
+ <item quantity="one">Η κάρτα SIM απενεργοποιήθηκε. Καταχωρίστε τον κωδικό PUK, για να συνεχίσετε. Απομένει <xliff:g id="_NUMBER_0">%d</xliff:g> ακόμη προσπάθεια προτού να μην είναι πλέον δυνατή η χρήση της κάρτας SIM. Επικοινωνήστε με την εταιρεία κινητής τηλεφωνίας για λεπτομέρειες.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index 0c5989b..df0c45b 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>
@@ -136,4 +135,12 @@
<item quantity="one">Hace <xliff:g id="NUMBER_0">%d</xliff:g> hora que no se desbloquea el dispositivo. Confirma la contraseña.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"No se reconoció"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Ingresa el PIN de la SIM. Te quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos más.</item>
+ <item quantity="one">Ingresa el PIN de la SIM. Te queda <xliff:g id="NUMBER_0">%d</xliff:g> intento antes de que debas comunicarte con tu proveedor para desbloquear el dispositivo.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">Se inhabilitó la SIM. Para continuar, ingresa el código PUK. Te quedan <xliff:g id="_NUMBER_1">%d</xliff:g> intentos más antes de que la SIM quede inutilizable permanentemente. Comunícate con tu proveedor para obtener más detalles.</item>
+ <item quantity="one">Se inhabilitó la SIM. Para continuar, ingresa el código PUK. Te queda <xliff:g id="_NUMBER_0">%d</xliff:g> intento más antes de que la SIM quede inutilizable permanentemente. Comunícate con tu proveedor para obtener más detalles.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index ac99a84..ec36fd7 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -135,4 +135,12 @@
<item quantity="one">El dispositivo no se ha desbloqueado durante <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirma la contraseña.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"No reconocido"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Introduce el PIN de la tarjeta SIM. Te quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos.</item>
+ <item quantity="one">Introduce el PIN de la tarjeta SIM. Te queda <xliff:g id="NUMBER_0">%d</xliff:g> para tener que ponerte en contacto con tu operador para desbloquear el dispositivo.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">La tarjeta SIM está inhabilitada. Introduce el código PUK para continuar. Te quedan <xliff:g id="_NUMBER_1">%d</xliff:g> intentos para que la tarjeta SIM quede inservible de forma permanente. Ponte en contacto con tu operador para obtener más información.</item>
+ <item quantity="one">La tarjeta SIM está inhabilitada. Introduce el código PUK para continuar. Te queda <xliff:g id="_NUMBER_0">%d</xliff:g> intento para que la tarjeta SIM quede inservible de forma permanente. Ponte en contacto con tu operador para obtener más información.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index 4c3cf6f..bca98ef 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>
@@ -136,4 +135,12 @@
<item quantity="one">Seadet pole avatud <xliff:g id="NUMBER_0">%d</xliff:g> tund. Kinnitage parool.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Ei tuvastatud"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Sisestage SIM-kaardi PIN-kood. Jäänud on <xliff:g id="NUMBER_1">%d</xliff:g> katset.</item>
+ <item quantity="one">Sisestage SIM-kaardi PIN-kood. Jäänud on <xliff:g id="NUMBER_0">%d</xliff:g> katse enne, kui peate seadme avamiseks ühendust võtma operaatoriga.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM-kaart on nüüd keelatud. Jätkamiseks sisestage PUK-kood. Teil on jäänud veel <xliff:g id="_NUMBER_1">%d</xliff:g> katset enne, kui SIM-kaart püsivalt lukustatakse. Lisateavet küsige operaatorilt.</item>
+ <item quantity="one">SIM-kaart on nüüd keelatud. Jätkamiseks sisestage PUK-kood. Teil on jäänud veel <xliff:g id="_NUMBER_0">%d</xliff:g> katse enne, kui SIM-kaart püsivalt lukustatakse. Lisateavet küsige operaatorilt.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index f7f3d58..3d79ae2 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>
@@ -136,4 +135,12 @@
<item quantity="one">Gailua ez da desblokeatu <xliff:g id="NUMBER_0">%d</xliff:g> orduz. Berretsi pasahitza.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Ez da ezagutu"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Idatzi SIM txartelaren PIN kodea. <xliff:g id="NUMBER_1">%d</xliff:g> saiakera geratzen zaizkizu.</item>
+ <item quantity="one">Idatzi SIM txartelaren PIN kodea. <xliff:g id="NUMBER_0">%d</xliff:g> saiakera geratzen zaizu; oker idatziz gero, operadoreari eskatu beharko diozu gailua desblokeatzeko.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">Desgaitu egin da SIM txartela. Aurrera egiteko, idatzi PUK kodea. <xliff:g id="_NUMBER_1">%d</xliff:g> saiakera geratzen zaizkizu SIM txartela betiko erabilgaitz geratu aurretik. Xehetasunak lortzeko, jarri operadorearekin harremanetan.</item>
+ <item quantity="one">Desgaitu egin da SIM txartela. Aurrera egiteko, idatzi PUK kodea. <xliff:g id="_NUMBER_0">%d</xliff:g> saiakera geratzen zaizu SIM txartela betiko erabilgaitz geratu aurretik. Xehetasunak lortzeko, jarri operadorearekin harremanetan.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index 43f8197..ce46e6a 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>
@@ -136,4 +135,12 @@
<item quantity="other">قفل دستگاه <xliff:g id="NUMBER_1">%d</xliff:g> ساعت باز نشده است. گذرواژه را تأیید کنید.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"شناسایی نشد"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <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>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">سیمکارت اکنون غیرفعال است. برای ادامه دادن کد PUK را وارد کنید. <xliff:g id="_NUMBER_1">%d</xliff:g> تلاش دیگر باقی مانده است و پس از آن سیمکارت برای همیشه غیرقابلاستفاده میشود. برای اطلاع از جزئیات با شرکت مخابراتی تماس بگیرید.</item>
+ <item quantity="other">سیمکارت اکنون غیرفعال است. برای ادامه دادن کد PUK را وارد کنید. <xliff:g id="_NUMBER_1">%d</xliff:g> تلاش دیگر باقی مانده است و پس از آن سیمکارت برای همیشه غیرقابلاستفاده میشود. برای اطلاع از جزئیات با شرکت مخابراتی تماس بگیرید.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index dc2a441..2b14e3c 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -135,4 +135,12 @@
<item quantity="one">Laitteen lukitusta ei ole avattu <xliff:g id="NUMBER_0">%d</xliff:g> tuntiin. Vahvista salasana.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Ei tunnistettu"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Anna SIM-kortin PIN-koodi. Sinulla on <xliff:g id="NUMBER_1">%d</xliff:g> yritystä jäljellä.</item>
+ <item quantity="one">Anna SIM-kortin PIN-koodi. <xliff:g id="NUMBER_0">%d</xliff:g> yrityksen jälkeen laite lukittuu, ja vain operaattori voi avata sen.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM-kortti on nyt lukittu. Anna PUK-koodi, niin voit jatkaa. Sinulla on <xliff:g id="_NUMBER_1">%d</xliff:g> yritystä jäljellä, ennen kuin SIM-kortti poistuu pysyvästi käytöstä. Pyydä lisätietoja operaattoriltasi.</item>
+ <item quantity="one">SIM-kortti on nyt lukittu. Anna PUK-koodi, niin voit jatkaa. Sinulla on <xliff:g id="_NUMBER_0">%d</xliff:g> yritys jäljellä, ennen kuin SIM-kortti poistuu pysyvästi käytöstä. Pyydä lisätietoja operaattoriltasi.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index 8e614e0..b033311 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -135,4 +135,12 @@
<item quantity="other">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heures. Confirmez le mot de passe.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Doigt non reconnu"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Entrez le NIP de votre carte SIM. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative.</item>
+ <item quantity="other">Entrez le NIP de votre carte SIM. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM devienne définitivement inutilisable. Pour obtenir plus de détails, communiquez avec votre fournisseur de services.</item>
+ <item quantity="other">La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM devienne définitivement inutilisable. Pour obtenir plus de détails, communiquez avec votre fournisseur de services.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index 1e7548e1..34b638e 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>
@@ -136,4 +135,12 @@
<item quantity="other">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heures. Confirmez le mot de passe.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Non reconnu"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Saisissez le code PIN de la carte SIM. <xliff:g id="NUMBER_1">%d</xliff:g> tentative restante.</item>
+ <item quantity="other">Saisissez le code PIN de la carte SIM. <xliff:g id="NUMBER_1">%d</xliff:g> tentatives restantes.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">La carte SIM est maintenant désactivée. Saisissez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM ne devienne définitivement inutilisable. Pour de plus amples informations, veuillez contacter votre opérateur.</item>
+ <item quantity="other">La carte SIM est maintenant désactivée. Saisissez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM ne devienne définitivement inutilisable. Pour de plus amples informations, veuillez contacter votre opérateur.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 7be5f41..e21e844 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -135,4 +135,12 @@
<item quantity="one">O dispositivo non se desbloqueou durante <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirma o contrasinal.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Non se recoñece"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Introduce o código PIN da SIM. Quédanche <xliff:g id="NUMBER_1">%d</xliff:g> intentos.</item>
+ <item quantity="one">Introduce o código PIN da SIM. Quédache <xliff:g id="NUMBER_0">%d</xliff:g> intento antes de que teñas que contactar co operador para desbloquear o dispositivo.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">A SIM está desactivada. Introduce o código PUK para continuar. Quédanche <xliff:g id="_NUMBER_1">%d</xliff:g> intentos antes de que a SIM quede inutilizable para sempre. Contacta co operador para obter información.</item>
+ <item quantity="one">A SIM está desactivada. Introduce o código PUK para continuar. Quédache <xliff:g id="_NUMBER_0">%d</xliff:g> intento antes de que a SIM quede inutilizable para sempre. Contacta co operador para obter información.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index 48aa75b..a6ee9a6 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -135,4 +135,6 @@
<item quantity="other">ઉપકરણને <xliff:g id="NUMBER_1">%d</xliff:g> કલાક માટે અનલૉક કરવામાં આવ્યું નથી. પાસવર્ડની પુષ્ટિ કરો.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"ઓળખાયેલ નથી"</string>
+ <!-- no translation found for kg_password_default_pin_message (6203676909479972943) -->
+ <!-- no translation found for kg_password_default_puk_message (8744416410184198352) -->
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index 62ed064..641c072 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -134,5 +134,13 @@
<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>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <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>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">सिम बंद कर दिया गया है. जारी रखने के लिए PUK कोड डालें. आपके पास <xliff:g id="_NUMBER_1">%d</xliff:g> मौके बचे हैं, उसके बाद, सिम हमेशा के लिए काम करना बंद कर देगा. जानकारी के लिए, मोबाइल और इंटरनेट सेवा देने वाली कंपनी से संपर्क करें.</item>
+ <item quantity="other">सिम बंद कर दिया गया है. जारी रखने के लिए PUK कोड डालें. आपके पास <xliff:g id="_NUMBER_1">%d</xliff:g> मौके बचे हैं, उसके बाद, सिम हमेशा के लिए काम करना बंद कर देगा. जानकारी के लिए, मोबाइल और इंटरनेट सेवा देने वाली कंपनी से संपर्क करें.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml
index 34c3a5a..cfdf5cd 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>
@@ -142,4 +141,14 @@
<item quantity="other">Uređaj nije bio otključan <xliff:g id="NUMBER_1">%d</xliff:g> sati. Potvrdite zaporku.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Nije prepoznat"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Unesite PIN za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
+ <item quantity="few">Unesite PIN za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
+ <item quantity="other">Unesite PIN za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaj prije nego što SIM kartica postane trajno neupotrebljiva. Više informacija zatražite od mobilnog operatera.</item>
+ <item quantity="few">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Više informacija zatražite od mobilnog operatera.</item>
+ <item quantity="other">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Više informacija zatražite od mobilnog operatera.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml
index a1922ee..71f34a9 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>
@@ -136,4 +135,12 @@
<item quantity="one">Az eszköz zárolása <xliff:g id="NUMBER_0">%d</xliff:g> órája nem lett feloldva. Erősítse meg a jelszót.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Nem sikerült felismerni"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Adja meg a SIM-kártya PIN-kódját. <xliff:g id="NUMBER_1">%d</xliff:g> próbálkozása maradt.</item>
+ <item quantity="one">Adja meg a SIM-kártya PIN-kódját. <xliff:g id="NUMBER_0">%d</xliff:g> próbálkozása maradt. Ha elfogynak a próbálkozási lehetőségek, az eszköz feloldásához fel kell vennie a kapcsolatot szolgáltatójával.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">A SIM-kártya le van tiltva. A folytatáshoz adja meg a PUK-kódot. Még <xliff:g id="_NUMBER_1">%d</xliff:g> próbálkozása van, mielőtt végleg használhatatlanná válik a SIM-kártya. További információért forduljon a szolgáltatóhoz.</item>
+ <item quantity="one">A SIM-kártya le van tiltva. A folytatáshoz adja meg a PUK-kódot. Még <xliff:g id="_NUMBER_0">%d</xliff:g> próbálkozása van, mielőtt végleg használhatatlanná válik a SIM-kártya. További információért forduljon a szolgáltatóhoz.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index 7914b5f..2936935 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -135,4 +135,12 @@
<item quantity="other">Սարքը չի ապակողպվել <xliff:g id="NUMBER_1">%d</xliff:g> ժամվա ընթացքում: Հաստատեք գաղտնաբառը:</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Չճանաչվեց"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Մուտքագրեք SIM քարտի PIN կոդը: Մնացել է <xliff:g id="NUMBER_1">%d</xliff:g> փորձ:</item>
+ <item quantity="other">Մուտքագրեք SIM քարտի PIN կոդը: Մնացել է <xliff:g id="NUMBER_1">%d</xliff:g> փորձ:</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">SIM քարտն անջատված է: Շարունակելու համար մուտքագրեք PUK կոդը: Մնացել է <xliff:g id="_NUMBER_1">%d</xliff:g> փորձ, որից հետո SIM քարտն այլևս հնարավոր չի լինի օգտագործել: Մանրամասների համար դիմեք օպերատորին:</item>
+ <item quantity="other">SIM քարտն անջատված է: Շարունակելու համար մուտքագրեք PUK կոդը: Մնացել է <xliff:g id="_NUMBER_1">%d</xliff:g> փորձ, որից հետո SIM քարտն այլևս հնարավոր չի լինի օգտագործել: Մանրամասների համար դիմեք օպերատորին:</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index e417a3f..ee3621c 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -135,4 +135,12 @@
<item quantity="one">Perangkat belum dibuka kuncinya selama <xliff:g id="NUMBER_0">%d</xliff:g> jam. Konfirmasi sandi.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Tidak dikenali"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Masukkan PIN SIM, tersisa <xliff:g id="NUMBER_1">%d</xliff:g> percobaan.</item>
+ <item quantity="one">Masukkan PIN SIM, tersisa <xliff:g id="NUMBER_0">%d</xliff:g> percobaan sebelum Anda harus menghubungi operator untuk membuka kunci perangkat.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM kini dinonaktifkan. Masukkan kode PUK untuk melanjutkan. Tersisa <xliff:g id="_NUMBER_1">%d</xliff:g> percobaan sebelum SIM tidak dapat digunakan secara permanen. Hubungi operator untuk mengetahui detailnya.</item>
+ <item quantity="one">SIM kini dinonaktifkan. Masukkan kode PUK untuk melanjutkan. Tersisa <xliff:g id="_NUMBER_0">%d</xliff:g> percobaan sebelum SIM tidak dapat digunakan secara permanen. Hubungi operator untuk mengetahui detailnya.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index 191c66e..cead5c4 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>
@@ -136,4 +135,12 @@
<item quantity="other">Tækið hefur ekki verið tekið úr lás í <xliff:g id="NUMBER_1">%d</xliff:g> klukkustundir. Staðfestu aðgangsorðið.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Þekktist ekki"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Sláðu inn PIN-númer SIM-korts. Það er <xliff:g id="NUMBER_1">%d</xliff:g> tilraun eftir.</item>
+ <item quantity="other">Sláðu inn PIN-númer SIM-korts. Það eru <xliff:g id="NUMBER_1">%d</xliff:g> tilraunir eftir.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">SIM-kortið er nú óvirkt. Sláðu inn PUK-númer til að halda áfram. Það er <xliff:g id="_NUMBER_1">%d</xliff:g> tilraun eftir þar til SIM-kortið verður ónothæft til frambúðar. Hafðu samband við símafyrirtækið til að fá upplýsingar.</item>
+ <item quantity="other">SIM-kortið er nú óvirkt. Sláðu inn PUK-númer til að halda áfram. Það eru <xliff:g id="_NUMBER_1">%d</xliff:g> tilraunir eftir þar til SIM-kortið verður ónothæft til frambúðar. Hafðu samband við símafyrirtækið til að fá upplýsingar.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 9ea32df..001f90c 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>
@@ -136,4 +135,12 @@
<item quantity="one">Il dispositivo non viene sbloccato da <xliff:g id="NUMBER_0">%d</xliff:g> ora. Conferma la password.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Non riconosciuta"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Inserisci il codice PIN della SIM. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione.</item>
+ <item quantity="one">Inserisci il codice PIN della SIM. Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile. Contatta l\'operatore per avere informazioni dettagliate.</item>
+ <item quantity="one">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile. Contatta l\'operatore per avere informazioni dettagliate.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml
index cb61b7d..8be3a89 100644
--- a/packages/SystemUI/res-keyguard/values-iw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml
@@ -147,4 +147,16 @@
<item quantity="one">נעילת המכשיר לא בוטלה במשך <xliff:g id="NUMBER_0">%d</xliff:g> שעה. הזן את הסיסמה.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"לא זוהתה"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="two">יש להזין PIN של כרטיס SIM, נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות נוספים.</item>
+ <item quantity="many">יש להזין PIN של כרטיס SIM, נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות נוספים.</item>
+ <item quantity="other">יש להזין PIN של כרטיס SIM, נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות נוספים.</item>
+ <item quantity="one">יש להזין PIN של כרטיס SIM. נותר לך <xliff:g id="NUMBER_0">%d</xliff:g> ניסיון נוסף לפני שיהיה צורך ליצור קשר עם הספק כדי לבטל את נעילת המכשיר.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="two">כרטיס ה-SIM מושבת כעת. יש להזין קוד PUK כדי להמשיך. נותרו לך <xliff:g id="_NUMBER_1">%d</xliff:g> ניסיונות נוספים לפני שכרטיס ה-SIM ינעל לצמיתות. למידע נוסף, ניתן לפנות לספק שלך.</item>
+ <item quantity="many">כרטיס ה-SIM מושבת כעת. יש להזין קוד PUK כדי להמשיך. נותרו לך <xliff:g id="_NUMBER_1">%d</xliff:g> ניסיונות נוספים לפני שכרטיס ה-SIM ינעל לצמיתות. למידע נוסף, ניתן לפנות לספק שלך.</item>
+ <item quantity="other">כרטיס ה-SIM מושבת כעת. יש להזין קוד PUK כדי להמשיך. נותרו לך <xliff:g id="_NUMBER_1">%d</xliff:g> ניסיונות נוספים לפני שכרטיס ה-SIM ינעל לצמיתות. למידע נוסף, ניתן לפנות לספק שלך.</item>
+ <item quantity="one">כרטיס ה-SIM מושבת כעת. יש להזין קוד PUK כדי להמשיך. נותר לך <xliff:g id="_NUMBER_0">%d</xliff:g> ניסיון נוסף לפני שכרטיס ה-SIM ינעל לצמיתות. למידע נוסף, ניתן לפנות לספק שלך.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml
index 4b5be4f..6bdc200 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>
@@ -136,4 +135,12 @@
<item quantity="one">端末のロックが <xliff:g id="NUMBER_0">%d</xliff:g> 時間、解除されていません。パスワードを確認してください。</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"認識されませんでした"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">SIM PIN を入力してください。入力できるのはあと <xliff:g id="NUMBER_1">%d</xliff:g> 回です。</item>
+ <item quantity="one">SIM PIN を入力してください。入力できるのはあと <xliff:g id="NUMBER_0">%d</xliff:g> 回です。この回数を超えた場合は、携帯通信会社にお問い合わせください。</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM が無効になりました。続行するには PUK コードを入力してください。入力できるのはあと <xliff:g id="_NUMBER_1">%d</xliff:g> 回です。この回数を超えると SIM は完全に使用できなくなります。詳しくは携帯通信会社にお問い合わせください。</item>
+ <item quantity="one">SIM が無効になりました。続行するには PUK コードを入力してください。入力できるのはあと <xliff:g id="_NUMBER_0">%d</xliff:g> 回です。この回数を超えると SIM は完全に使用できなくなります。詳しくは携帯通信会社にお問い合わせください。</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml
index 5da8122..31ccaae 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>
@@ -136,4 +135,12 @@
<item quantity="one">მოწყობილობა არ განბლოკილა <xliff:g id="NUMBER_0">%d</xliff:g> საათის განმავლობაში. დაადასტურეთ პაროლი.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"არ არის ამოცნობილი"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">შეიყვანეთ SIM ბარათის PIN-კოდი. თქვენ დაგრჩათ <xliff:g id="NUMBER_1">%d</xliff:g> მცდელობა.</item>
+ <item quantity="one">შეიყვანეთ SIM ბარათის PIN-კოდი. თქვენ დაგრჩათ <xliff:g id="NUMBER_0">%d</xliff:g> მცდელობა, რომლის შემდეგაც მოწყობილობის განსაბლოკად დაგჭირდებათ თქვენს ოპერატორთან დაკავშირება.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM ბარათი ახლა დეაქტივირებულია. გასაგრძელებლად შეიყვანეთ PUK-კოდი. თქვენ დაგრჩათ <xliff:g id="_NUMBER_1">%d</xliff:g> მცდელობა, სანამ SIM სამუდამოდ გამოუსადეგარი გახდება. დეტალური ინფორმაციისთვის დაუკავშირდით თქვენს ოპერატორს.</item>
+ <item quantity="one">SIM ბარათი ახლა დეაქტივირებულია. გასაგრძელებლად შეიყვანეთ PUK-კოდი. თქვენ დაგრჩათ <xliff:g id="_NUMBER_0">%d</xliff:g> მცდელობა, სანამ SIM სამუდამოდ გამოუსადეგარი გახდება. დეტალური ინფორმაციისთვის დაუკავშირდით თქვენს ოპერატორს.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index a99f2ec..f9e12f1 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>
@@ -136,4 +135,12 @@
<item quantity="one">Құрылғы құлпы <xliff:g id="NUMBER_0">%d</xliff:g> сағаттан бері ашылмаған. Құпия сөзді растаңыз.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Анықталмады"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">SIM PIN кодын енгізіңіз. <xliff:g id="NUMBER_1">%d</xliff:g> мүмкіндік қалды.</item>
+ <item quantity="one">SIM PIN кодын енгізіңіз. <xliff:g id="NUMBER_0">%d</xliff:g> мүмкіндік қалды, одан кейін оператордан SIM картасының құлпын ашуды сұрауға тура келеді.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM картасы өшірілді. Жалғастыру үшін PUK кодын енгізіңіз. <xliff:g id="_NUMBER_1">%d</xliff:g> мүмкіндік қалды, одан кейін SIM картасы біржола құлыпталады. Толығырақ мәліметті оператордан алыңыз.</item>
+ <item quantity="one">SIM картасы өшірілді. Жалғастыру үшін PUK кодын енгізіңіз. <xliff:g id="_NUMBER_0">%d</xliff:g> мүмкіндік қалды, одан кейін SIM картасы біржола құлыпталады. Толығырақ мәліметті оператордан алыңыз.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 7241ac3..3bf4379 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>
@@ -136,4 +135,12 @@
<item quantity="one">ឧបករណ៍បានជាប់សោអស់រយៈពេល <xliff:g id="NUMBER_0">%d</xliff:g> ម៉ោងហើយ។ សូមបញ្ជាក់ពាក្យសម្ងាត់។</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"មិនអាចសម្គាល់បានទេ"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">បញ្ចូលកូដ PIN របស់ស៊ីម អ្នកនៅសល់ការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត។</item>
+ <item quantity="one">បញ្ចូលកូដ PIN របស់ស៊ីម អ្នកនៅសល់ការព្យាយាម <xliff:g id="NUMBER_0">%d</xliff:g> ដងទៀត មុនពេលដែលអ្នកត្រូវទាក់ទងទៅក្រុមហ៊ុនសេវាទូរសព្ទរបស់អ្នកដើម្បីដោះសោឧបករណ៍របស់អ្នក។</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">ឥឡូវនេះស៊ីមត្រូវបានបិទ។ សូមបញ្ចូលកូដ PUK ដើម្បីបន្ត។ អ្នកនៅសល់ការព្យាយាម <xliff:g id="_NUMBER_1">%d</xliff:g> ដងទៀតមុនពេលស៊ីមមិនអាចប្រើបានជាអចិន្ត្រៃយ៍។ ទាក់ទងទៅក្រុមហ៊ុនសេវាទូរសព្ទសម្រាប់ព័ត៌មានលម្អិត។</item>
+ <item quantity="one">ឥឡូវនេះស៊ីមត្រូវបានបិទ។ សូមបញ្ចូលកូដ PUK ដើម្បីបន្ត។ អ្នកនៅសល់ការព្យាយាម <xliff:g id="_NUMBER_0">%d</xliff:g> ដងទៀតមុនពេលស៊ីមមិនអាចប្រើបានជាអចិន្ត្រៃយ៍។ ទាក់ទងទៅក្រុមហ៊ុនសេវាទូរសព្ទសម្រាប់ព័ត៌មានលម្អិត។</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index 093c5cb..2ee30e9 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -135,4 +135,6 @@
<item quantity="other">ಸಾಧನವನ್ನು <xliff:g id="NUMBER_1">%d</xliff:g> ಗಂಟೆಗಳವರೆಗೆ ಅನ್ಲಾಕ್ ಮಾಡಿರಲಿಲ್ಲ. ಪಾಸ್ವರ್ಡ್ ಖಚಿತಪಡಿಸಿ.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
+ <!-- no translation found for kg_password_default_pin_message (6203676909479972943) -->
+ <!-- no translation found for kg_password_default_puk_message (8744416410184198352) -->
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index 9b48a4b..1a34229 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -135,4 +135,12 @@
<item quantity="one">기기가 <xliff:g id="NUMBER_0">%d</xliff:g>시간 동안 잠금 해제되지 않았습니다. 비밀번호를 입력하세요.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"인식할 수 없음"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">SIM PIN을 입력하세요. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 시도할 수 있습니다.</item>
+ <item quantity="one">SIM PIN을 입력하세요. <xliff:g id="NUMBER_0">%d</xliff:g>번 더 실패하면 이동통신사에 문의하여 기기를 잠금 해제해야 합니다.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM이 사용 중지되었습니다. 계속하려면 PUK 코드를 입력하세요. <xliff:g id="_NUMBER_1">%d</xliff:g>번 더 실패하면 SIM을 완전히 사용할 수 없게 됩니다. 자세한 내용은 이동통신사에 문의하세요.</item>
+ <item quantity="one">SIM이 사용 중지되었습니다. 계속하려면 PUK 코드를 입력하세요. <xliff:g id="_NUMBER_0">%d</xliff:g>번 더 실패하면 SIM을 완전히 사용할 수 없게 됩니다. 자세한 내용은 이동통신사에 문의하세요.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index ff27639..054ce7c 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>
@@ -136,4 +135,12 @@
<item quantity="one">Түзмөктүн кулпусу <xliff:g id="NUMBER_0">%d</xliff:g> саат бою ачылган жок. Сырсөздү ырастаңыз.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Таанылган жок"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">SIM-картанын PIN-кодун киргизиңиз, сизде <xliff:g id="NUMBER_1">%d</xliff:g> аракет калды.</item>
+ <item quantity="one">SIM-картанын PIN-кодун киргизиңиз, сизде <xliff:g id="NUMBER_0">%d</xliff:g> аракет калды. Эми түзмөктү бөгөттөн чыгаруу үчүн байланыш операторуңузга кайрылышыңыз керек.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM-карта азыр жарактан чыкты. Улантуу үчүн PUK-кодду киргизиңиз. SIM-картанын биротоло жарактан чыгарына <xliff:g id="_NUMBER_1">%d</xliff:g> аракет калды. Чоо-жайын билүү үчүн байланыш операторуна кайрылыңыз.</item>
+ <item quantity="one">SIM-карта азыр жарактан чыкты. Улантуу үчүн PUK-кодду киргизиңиз. SIM-картанын биротоло жарактан чыгарына <xliff:g id="_NUMBER_0">%d</xliff:g> аракет калды. Чоо-жайын билүү үчүн байланыш операторуна кайрылыңыз.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index 11823a3..545d32a 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>
@@ -134,4 +135,12 @@
<item quantity="one">ອຸປະກອນບໍ່ໄດ້ຖືກປົດລັອກເປັນເວລາ <xliff:g id="NUMBER_0">%d</xliff:g> ຊົ່ວໂມງ. ຢືນຢັນລະຫັດຜ່ານ.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"ບໍ່ຮັບຮູ້"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">ລະຫັດ PIN ຂອງ SIM ບໍ່ຖືກຕ້ອງ, ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ເທື່ອ.</item>
+ <item quantity="one">ລະຫັດ PIN ຂອງ SIM ບໍ່ຖືກຕ້ອງ, ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອກ່ອນທີ່ທ່ານຈະຕ້ອງຕິດຕໍ່ຫາຜູ້ໃຫ້ບໍລິການຂອງທ່ານເພື່ອປົດລັອກອຸປະກອນທ່ານ.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">ຕອນນີ້ປິດການນຳໃຊ້ SIM ແລ້ວ. ໃສ່ລະຫັດ PUK ເພື່ອດຳເນີນການຕໍ່. ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="_NUMBER_1">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຈະບໍ່ສາມາດໃຊ້ໄດ້ຖາວອນ. ກະລຸນາຕິດຕໍ່ຜູ້ໃຫ້ບໍລິການສຳລັບລາຍລະອຽດ.</item>
+ <item quantity="one">ຕອນນີ້ປິດການນຳໃຊ້ SIM ແລ້ວ. ໃສ່ລະຫັດ PUK ເພື່ອດຳເນີນການຕໍ່. ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="_NUMBER_0">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຈະບໍ່ສາມາດໃຊ້ໄດ້ຖາວອນ. ກະລຸນາຕິດຕໍ່ຜູ້ໃຫ້ບໍລິການສຳລັບລາຍລະອຽດ.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml
index 9e59fb1..bf041a0 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>
@@ -148,4 +147,16 @@
<item quantity="other">Įrenginys nebuvo atrakintas <xliff:g id="NUMBER_1">%d</xliff:g> valandų. Patvirtinkite slaptažodį.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Neatpažinta"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Įveskite SIM kortelės PIN kodą. Jums liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymas.</item>
+ <item quantity="few">Įveskite SIM kortelės PIN kodą. Jums liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymai.</item>
+ <item quantity="many">Įveskite SIM kortelės PIN kodą. Jums liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymo.</item>
+ <item quantity="other">Įveskite SIM kortelės PIN kodą. Jums liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymų.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">SIM kortelė dabar yra išjungta. Jei norite tęsti, įveskite PUK kodą. Jums liko <xliff:g id="_NUMBER_1">%d</xliff:g> bandymas. Paskui visiškai nebegalėsite naudoti SIM kortelės. Jei reikia išsamios informacijos, susisiekite su operatoriumi.</item>
+ <item quantity="few">SIM kortelė dabar yra išjungta. Jei norite tęsti, įveskite PUK kodą. Jums liko <xliff:g id="_NUMBER_1">%d</xliff:g> bandymai. Paskui visiškai nebegalėsite naudoti SIM kortelės. Jei reikia išsamios informacijos, susisiekite su operatoriumi.</item>
+ <item quantity="many">SIM kortelė dabar yra išjungta. Jei norite tęsti, įveskite PUK kodą. Jums liko <xliff:g id="_NUMBER_1">%d</xliff:g> bandymo. Paskui visiškai nebegalėsite naudoti SIM kortelės. Jei reikia išsamios informacijos, susisiekite su operatoriumi.</item>
+ <item quantity="other">SIM kortelė dabar yra išjungta. Jei norite tęsti, įveskite PUK kodą. Jums liko <xliff:g id="_NUMBER_1">%d</xliff:g> bandymų. Paskui visiškai nebegalėsite naudoti SIM kortelės. Jei reikia išsamios informacijos, susisiekite su operatoriumi.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index 3447973..475e9ce 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>
@@ -142,4 +141,14 @@
<item quantity="other">Ierīce nav tikusi atbloķēta <xliff:g id="NUMBER_1">%d</xliff:g> stundas. Apstipriniet paroli.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Nav atpazīts"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="zero">Ievadiet SIM kartes PIN kodu. Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizes.</item>
+ <item quantity="one">Ievadiet SIM kartes PIN kodu. Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizi.</item>
+ <item quantity="other">Ievadiet SIM kartes PIN kodu. Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizes.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="zero">SIM karte tagad ir atspējota. Ievadiet PUK kodu, lai turpinātu. Varat mēģināt vēl <xliff:g id="_NUMBER_1">%d</xliff:g> reizes. Kļūdas gadījumā SIM karti vairs nevarēs izmantot. Lai iegūtu detalizētu informāciju, sazinieties ar mobilo sakaru operatoru.</item>
+ <item quantity="one">SIM karte tagad ir atspējota. Ievadiet PUK kodu, lai turpinātu. Varat mēģināt vēl <xliff:g id="_NUMBER_1">%d</xliff:g> reizi. Kļūdas gadījumā SIM karti vairs nevarēs izmantot. Lai iegūtu detalizētu informāciju, sazinieties ar mobilo sakaru operatoru.</item>
+ <item quantity="other">SIM karte tagad ir atspējota. Ievadiet PUK kodu, lai turpinātu. Varat mēģināt vēl <xliff:g id="_NUMBER_1">%d</xliff:g> reizes. Kļūdas gadījumā SIM karti vairs nevarēs izmantot. Lai iegūtu detalizētu informāciju, sazinieties ar mobilo sakaru operatoru.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index 263b3c9..0951787 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>
@@ -136,4 +135,12 @@
<item quantity="other">Уредот не е отклучен веќе <xliff:g id="NUMBER_1">%d</xliff:g> часа. Потврдете ја лозинката.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Непознат"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Внесете PIN-код за SIM-картичката. Ви преостанува уште <xliff:g id="NUMBER_1">%d</xliff:g> обид.</item>
+ <item quantity="other">Внесете PIN-код за SIM-картичката. Ви преостануваат уште <xliff:g id="NUMBER_1">%d</xliff:g> обиди.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">SIM-картичката сега е оневозможена. Внесете PUK-код за да продолжите. Ви преостанува уште <xliff:g id="_NUMBER_1">%d</xliff:g> обид пред SIM-картичката да стане трајно неупотреблива. Контактирајте го операторот за детали.</item>
+ <item quantity="other">SIM-картичката сега е оневозможена. Внесете PUK-код за да продолжите. Ви преостануваат уште <xliff:g id="_NUMBER_1">%d</xliff:g> обиди пред SIM-картичката да стане трајно неупотреблива. Контактирајте го операторот за детали.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index 0b21231..7f0e957 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -135,4 +135,6 @@
<item quantity="one">ഉപകരണം <xliff:g id="NUMBER_0">%d</xliff:g> മണിക്കൂറായി അൺലോക്ക് ചെയ്തിട്ടില്ല. പാസ്വേഡ് സ്ഥിരീകരിക്കുക.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"തിരിച്ചറിഞ്ഞില്ല"</string>
+ <!-- no translation found for kg_password_default_pin_message (6203676909479972943) -->
+ <!-- no translation found for kg_password_default_puk_message (8744416410184198352) -->
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index 44c186f..5f9b63d 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>
@@ -136,4 +135,12 @@
<item quantity="one">Төхөөрөмжийн түгжээг <xliff:g id="NUMBER_0">%d</xliff:g> цагийн турш тайлаагүй байна. Нууц үгээ баталгаажуулна уу.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Танигдахгүй байна"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">SIM-н ПИН кодыг оруулна уу. Танд <xliff:g id="NUMBER_1">%d</xliff:g> оролдлого үлдлээ.</item>
+ <item quantity="one">SIM-н ПИН кодыг оруулна уу. Танд оператор компанитайгаа холбогдохгүйгээр төхөөрөмжийн түгжээг тайлах <xliff:g id="NUMBER_0">%d</xliff:g> оролдлого үлдлээ.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM-г идэвхгүй болголоо. Үргэлжлүүлэхийн тулд PUK кодыг оруулна уу. Таны SIM бүрмөсөн хүчингүй болох хүртэл <xliff:g id="_NUMBER_1">%d</xliff:g> оролдлого үлдлээ. Дэлгэрэнгүй мэдээлэл авахын тулд оператор компанитайгаа холбогдоно уу.</item>
+ <item quantity="one">SIM-г идэвхгүй болголоо. Үргэлжлүүлэхийн тулд PUK кодыг оруулна уу. Таны SIM бүрмөсөн хүчингүй болох хүртэл <xliff:g id="_NUMBER_0">%d</xliff:g> оролдлого үлдлээ. Дэлгэрэнгүй мэдээлэл авахын тулд оператор компанитайгаа холбогдоно уу.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index cfda6cc..7d04edc 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -135,4 +135,12 @@
<item quantity="other">डिव्हाइस <xliff:g id="NUMBER_1">%d</xliff:g> तासांसाठी अनलॉक केले गेले नाही. पासवर्डची खात्री करा.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"ओळखले नाही"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <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>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">सिम आता बंद केलेले आहे. सुरू ठेवण्यासाठी PUK कोड टाका. सिम कायमचे बंद होण्याआधी तुमच्याकडे <xliff:g id="_NUMBER_1">%d</xliff:g> प्रयत्न शिल्लक आहे. तपशीलांसाठी वाहकाशी संपर्क साधा.</item>
+ <item quantity="other">सिम आता बंद केलेले आहे. सुरू ठेवण्यासाठी PUK कोड टाका. सिम कायमचे बंद होण्याआधी तुमच्याकडे <xliff:g id="_NUMBER_1">%d</xliff:g> प्रयत्न शिल्लक आहेत. तपशीलांसाठी वाहकाशी संपर्क साधा.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index efffa8c..d37e7ee 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>
@@ -136,4 +135,12 @@
<item quantity="one">Peranti tidak dibuka kuncinya selama <xliff:g id="NUMBER_0">%d</xliff:g> jam. Sahkan kata laluan.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Tidak dikenali"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Masukkan PIN SIM, tinggal <xliff:g id="NUMBER_1">%d</xliff:g> percubaan lagi.</item>
+ <item quantity="one">Masukkan PIN SIM, tinggal <xliff:g id="NUMBER_0">%d</xliff:g> percubaan lagi sebelum anda harus menghubungi pembawa anda untuk membuka kunci peranti.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">Kini SIM dilumpuhkan. Masukkan kod PUK untuk meneruskan. Tinggal <xliff:g id="_NUMBER_1">%d</xliff:g> percubaan sebelum SIM tidak boleh digunakan secara kekal. Hubungi pembawa untuk mendapatkan butiran.</item>
+ <item quantity="one">Kini SIM dilumpuhkan. Masukkan kod PUK untuk meneruskan. Tinggal <xliff:g id="_NUMBER_0">%d</xliff:g> percubaan sebelum SIM tidak boleh digunakan secara kekal. Hubungi pembawa untuk mendapatkan butiran.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index 7b598e1..6534fbb 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>
@@ -136,4 +135,12 @@
<item quantity="one">စက်ပစ္စည်းကို <xliff:g id="NUMBER_0">%d</xliff:g> နာရီကြာ လော့ခ်ဖွင့်ခဲ့ခြင်း မရှိပါ။ စကားဝှက်အား အတည်ပြုပါ။</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"မသိပါ"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">ဆင်းမ်ကဒ် ပင်နံပါတ် ထည့်သွင်းပါ၊ သင့်တွင် <xliff:g id="NUMBER_1">%d</xliff:g> ခါ ကြိုးစားခွင့် ကျန်ပါသေးသည်။</item>
+ <item quantity="one">ဆင်းမ်ကဒ် ပင်နံပါတ် ထည့်သွင်းပါ၊ သင့်စက်ကို ဖွင့်ရန် ဝန်ဆောင်မှုပေးသူသို့ မဆက်သွယ်မီ သင့်တွင် <xliff:g id="NUMBER_0">%d</xliff:g> ခါ ကြိုးစားခွင့် ကျန်ပါသေးသည်။</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">ဆင်းမ်ကဒ်သည် ယခု ပိတ်သွားပါပြီ။ ရှေ့ဆက်ရန် ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ်ကို ထည့်ပါ။ ဆင်းမ်ကဒ်ကို အပြီးသုံးမရအောင်မပြုမီ သင့်တွင် <xliff:g id="_NUMBER_1">%d</xliff:g> ခါ ကြိုးစားခွင့်ကျန်ပါသေးသည်။ အသေးစိတ်အချက်များအတွက် ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ပါ။</item>
+ <item quantity="one">ဆင်းမ်ကဒ်သည် ယခု ပိတ်သွားပါပြီ။ ရှေ့ဆက်ရန် ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ်ကို ထည့်ပါ။ ဆင်းမ်ကဒ်ကို အပြီးသုံးမရအောင်မပြုမီ သင့်တွင် <xliff:g id="_NUMBER_0">%d</xliff:g> ခါ ကြိုးစားခွင့်ကျန်ပါသေးသည်။ အသေးစိတ်အချက်များအတွက် ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ပါ။</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index 1fef576..ca51c96 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>
@@ -136,4 +135,12 @@
<item quantity="one">Enheten har ikke blitt låst opp på <xliff:g id="NUMBER_0">%d</xliff:g> time. Bekreft passordet.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Ikke gjenkjent"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Skriv inn PIN-koden for SIM-kortet. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøk igjen.</item>
+ <item quantity="one">Skriv inn PIN-koden for SIM-kortet. Du har <xliff:g id="NUMBER_0">%d</xliff:g> forsøk igjen før du må kontakte operatøren din for å låse opp enheten.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM-kortet er deaktivert nå. Skriv inn PUK-koden for å fortsette. Du har <xliff:g id="_NUMBER_1">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig. Kontakt operatøren for å få vite mer.</item>
+ <item quantity="one">SIM-kortet er deaktivert nå. Skriv inn PUK-koden for å fortsette. Du har <xliff:g id="_NUMBER_0">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig. Kontakt operatøren for å få vite mer.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index d5ac1d8..90d6c5cfc 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -135,4 +135,12 @@
<item quantity="one">यन्त्र <xliff:g id="NUMBER_0">%d</xliff:g> घन्टा देखि अनलक भएको छैन। पासवर्ड पुष्टि गर्नुहोस्।</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"पहिचान भएन"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">SIM को PIN प्रविष्ट गर्नुहोस् तपाईंसँग <xliff:g id="NUMBER_1">%d</xliff:g> प्रयासहरू बाँकी छन्।</item>
+ <item quantity="one">SIM को PIN प्रविष्ट गर्नुहोस्, तपाईंसँग <xliff:g id="NUMBER_0">%d</xliff:g> प्रयास बाँकी छ, त्यसपछि भने आफ्नो यन्त्र अनलक गर्नका लागि तपाईंले अनिवार्य रूपमा आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नपर्ने हुन्छ।</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM लाई असक्षम पारिएको छ। जारी राख्न PUK कोड प्रविष्ट गर्नुहोस्। तपाईंसँग <xliff:g id="_NUMBER_1">%d</xliff:g> प्रयासहरू बाँकी छन्, त्यसपछि SIM सदाका लागि प्रयोग गर्न नमिल्ने हुन्छ। विवरणहरूका लागि सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।</item>
+ <item quantity="one">SIM लाई असक्षम पारिएको छ। जारी राख्न PUK कोड प्रविष्ट गर्नुहोस्। तपाईंसँग <xliff:g id="_NUMBER_0">%d</xliff:g> प्रयास बाँकी छ, त्यसपछि SIM सदाका लागि प्रयोग गर्न नमिल्ने हुन्छ। विवरणहरूका लागि सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index 6a1f3c9..85e0a95 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -135,4 +135,12 @@
<item quantity="one">Apparaat is al <xliff:g id="NUMBER_0">%d</xliff:g> uur niet ontgrendeld. Bevestig het wachtwoord.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Niet herkend"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Geef de pincode van de simkaart op. Je hebt nog <xliff:g id="NUMBER_1">%d</xliff:g> pogingen over.</item>
+ <item quantity="one">Geef de pincode van de simkaart op. Je hebt nog <xliff:g id="NUMBER_0">%d</xliff:g> poging over voordat je contact met je provider moet opnemen om het apparaat te ontgrendelen.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">De simkaart is nu uitgeschakeld. Geef de pukcode op om door te gaan. Je hebt nog <xliff:g id="_NUMBER_1">%d</xliff:g> pogingen over voordat de simkaart definitief onbruikbaar wordt. Neem contact op met je provider voor meer informatie.</item>
+ <item quantity="one">De simkaart is nu uitgeschakeld. Geef de pukcode op om door te gaan. Je hebt nog <xliff:g id="_NUMBER_0">%d</xliff:g> poging over voordat de simkaart definitief onbruikbaar wordt. Neem contact op met je provider voor meer informatie.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index 0bab97d..dc0e53ba 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -135,4 +135,6 @@
<item quantity="other">ਡੀਵਾਈਸ <xliff:g id="NUMBER_1">%d</xliff:g> ਘੰਟਿਆਂ ਤੋਂ ਅਣਲਾਕ ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਹੈ। ਪਾਸਵਰਡ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
+ <!-- no translation found for kg_password_default_pin_message (6203676909479972943) -->
+ <!-- no translation found for kg_password_default_puk_message (8744416410184198352) -->
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index 59f4412..ee6ad62 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -147,4 +147,16 @@
<item quantity="one">Urządzenie nie zostało odblokowane od <xliff:g id="NUMBER_0">%d</xliff:g> godziny. Potwierdź hasło.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Nie rozpoznano"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="few">Wpisz kod PIN karty SIM. Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> próby.</item>
+ <item quantity="many">Wpisz kod PIN karty SIM. Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> prób.</item>
+ <item quantity="other">Wpisz kod PIN karty SIM. Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> próby.</item>
+ <item quantity="one">Wpisz kod PIN karty SIM. Masz jeszcze <xliff:g id="NUMBER_0">%d</xliff:g> próbę, zanim będzie trzeba skontaktować się z operatorem, by odblokować to urządzenie.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="few">Karta SIM została wyłączona. Wpisz kod PUK, by przejść dalej. Masz jeszcze <xliff:g id="_NUMBER_1">%d</xliff:g> próby, zanim karta SIM zostanie trwale zablokowana. Aby uzyskać szczegółowe informacje, skontaktuj się z operatorem.</item>
+ <item quantity="many">Karta SIM została wyłączona. Wpisz kod PUK, by przejść dalej. Masz jeszcze <xliff:g id="_NUMBER_1">%d</xliff:g> prób, zanim karta SIM zostanie trwale zablokowana. Aby uzyskać szczegółowe informacje, skontaktuj się z operatorem.</item>
+ <item quantity="other">Karta SIM została wyłączona. Wpisz kod PUK, by przejść dalej. Masz jeszcze <xliff:g id="_NUMBER_1">%d</xliff:g> próby, zanim karta SIM zostanie trwale zablokowana. Aby uzyskać szczegółowe informacje, skontaktuj się z operatorem.</item>
+ <item quantity="one">Karta SIM została wyłączona. Wpisz kod PUK, by przejść dalej. Masz jeszcze <xliff:g id="_NUMBER_0">%d</xliff:g> próbę, zanim karta SIM zostanie trwale zablokowana. Aby uzyskać szczegółowe informacje, skontaktuj się z operatorem.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index 362ffcf..bb547f15 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -135,4 +135,12 @@
<item quantity="other">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme a senha.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Não reconhecido"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Informe o PIN do SIM. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativa restante.</item>
+ <item quantity="other">Informe o PIN do SIM. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativas restantes.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">O SIM agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativa restante antes de o SIM se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
+ <item quantity="other">O SIM agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas restantes antes de o SIM se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index 4f6fcb9..6a0e627 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,24 @@
<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>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Introduza o PIN do cartão SIM. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item>
+ <item quantity="one">Introduza o PIN do cartão SIM. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de ser necessário contactar o operador para desbloquear o dispositivo.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item>
+ <item quantity="one">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index 362ffcf..bb547f15 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -135,4 +135,12 @@
<item quantity="other">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme a senha.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Não reconhecido"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Informe o PIN do SIM. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativa restante.</item>
+ <item quantity="other">Informe o PIN do SIM. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativas restantes.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">O SIM agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativa restante antes de o SIM se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
+ <item quantity="other">O SIM agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas restantes antes de o SIM se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index d0dc17e..341c952 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -141,4 +141,14 @@
<item quantity="one">Dispozitivul nu a fost deblocat de <xliff:g id="NUMBER_0">%d</xliff:g> oră. Confirmați parola.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Nu este recunoscută"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="few">Introduceți codul PIN pentru cardul SIM. V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> încercări.</item>
+ <item quantity="other">Introduceți codul PIN pentru cardul SIM. V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> de încercări.</item>
+ <item quantity="one">Introduceți codul PIN pentru cardul SIM. V-a mai rămas <xliff:g id="NUMBER_0">%d</xliff:g> încercare, după care va trebui să contactați operatorul pentru a vă debloca dispozitivul.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="few">Cardul SIM este dezactivat acum. Introduceți codul PUK pentru a continua. V-au mai rămas <xliff:g id="_NUMBER_1">%d</xliff:g> încercări până când cardul SIM va deveni inutilizabil definitiv. Contactați operatorul pentru detalii.</item>
+ <item quantity="other">Cardul SIM este dezactivat acum. Introduceți codul PUK pentru a continua. V-au mai rămas <xliff:g id="_NUMBER_1">%d</xliff:g> de încercări până când cardul SIM va deveni inutilizabil definitiv. Contactați operatorul pentru detalii.</item>
+ <item quantity="one">Cardul SIM este dezactivat acum. Introduceți codul PUK pentru a continua. V-a mai rămas <xliff:g id="_NUMBER_0">%d</xliff:g> încercare până când cardul SIM va deveni inutilizabil definitiv. Contactați operatorul pentru detalii.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index 3f27010..1a794ee 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>
@@ -148,4 +147,16 @@
<item quantity="other">Устройство не разблокировалось в течение <xliff:g id="NUMBER_1">%d</xliff:g> часа. Введите пароль ещё раз.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Не распознано"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Неверный PIN-код. Осталась <xliff:g id="NUMBER_1">%d</xliff:g> попытка.</item>
+ <item quantity="few">Неверный PIN-код. Осталось <xliff:g id="NUMBER_1">%d</xliff:g> попытки.</item>
+ <item quantity="many">Неверный PIN-код. Осталось <xliff:g id="NUMBER_1">%d</xliff:g> попыток.</item>
+ <item quantity="other">Неверный PIN-код. Осталось <xliff:g id="NUMBER_1">%d</xliff:g> попытки.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">SIM-карта отключена. Чтобы продолжить, введите PUK-код. Осталась <xliff:g id="_NUMBER_1">%d</xliff:g> попытка. После этого SIM-карта будет заблокирована навсегда. За подробной информацией обратитесь к оператору связи.</item>
+ <item quantity="few">SIM-карта отключена. Чтобы продолжить, введите PUK-код. Осталось <xliff:g id="_NUMBER_1">%d</xliff:g> попытки. После этого SIM-карта будет заблокирована навсегда. За подробной информацией обратитесь к оператору связи.</item>
+ <item quantity="many">SIM-карта отключена. Чтобы продолжить, введите PUK-код. Осталось <xliff:g id="_NUMBER_1">%d</xliff:g> попыток. После этого SIM-карта будет заблокирована навсегда. За подробной информацией обратитесь к оператору связи.</item>
+ <item quantity="other">SIM-карта отключена. Чтобы продолжить, введите PUK-код. Осталось <xliff:g id="_NUMBER_1">%d</xliff:g> попытки. После этого SIM-карта будет заблокирована навсегда. За подробной информацией обратитесь к оператору связи.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index e48d81d..d36e752 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>
@@ -136,4 +135,12 @@
<item quantity="other">උපාංගය පැය <xliff:g id="NUMBER_1">%d</xliff:g>ක් අගුලු හැර නැත. මුරපදය තහවුරු කරන්න.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"හඳුනා නොගන්නා ලදී"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">SIM PIN ඇතුළු කරන්න, ඔබ සතුව උත්සාහයන් <xliff:g id="NUMBER_1">%d</xliff:g>ක් ඉතිරිව ඇත.</item>
+ <item quantity="other">SIM PIN ඇතුළු කරන්න, ඔබ සතුව උත්සාහයන් <xliff:g id="NUMBER_1">%d</xliff:g>ක් ඉතිරිව ඇත.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">SIM දැන් අබල කර ඇත. දිගටම කරගෙන යාමට PUK කේතය ඇතුළු කරන්න. SIM ස්ථිරවම භාවිත කළ නොහැකි බවට පත් වීමට පෙර ඔබ සතුව උත්සාහයන් <xliff:g id="_NUMBER_1">%d</xliff:g>ක් ඉතිරිව ඇත. විස්තර සඳහා වාහක සම්බන්ධ කර ගන්න.</item>
+ <item quantity="other">SIM දැන් අබල කර ඇත. දිගටම කරගෙන යාමට PUK කේතය ඇතුළු කරන්න. SIM ස්ථිරවම භාවිත කළ නොහැකි බවට පත් වීමට පෙර ඔබ සතුව උත්සාහයන් <xliff:g id="_NUMBER_1">%d</xliff:g>ක් ඉතිරිව ඇත. විස්තර සඳහා වාහක සම්බන්ධ කර ගන්න.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml
index 9f397e6..b69f502 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>
@@ -148,4 +147,16 @@
<item quantity="one">Zariadenie nebolo odomknuté <xliff:g id="NUMBER_0">%d</xliff:g> hodinu. Potvrďte heslo.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Nerozpoznané"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="few">Zadajte kód PIN SIM karty. Zostávajú vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusy.</item>
+ <item quantity="many">Zadajte kód PIN SIM karty. Zostáva vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusu.</item>
+ <item quantity="other">Zadajte kód PIN SIM karty. Zostáva vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusov.</item>
+ <item quantity="one">Zadajte kód PIN SIM karty. Zostáva vám <xliff:g id="NUMBER_0">%d</xliff:g> pokus, potom budete musieť kontaktovať svojho operátora, aby odomkol zariadenie.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="few">SIM karta je deaktivovaná. Pokračujte zadaním kódu PUK. Zostávajú vám <xliff:g id="_NUMBER_1">%d</xliff:g> pokusy, potom sa SIM karta natrvalo zablokuje. Podrobnosti vám poskytne operátor.</item>
+ <item quantity="many">SIM karta je deaktivovaná. Pokračujte zadaním kódu PUK. Zostáva vám <xliff:g id="_NUMBER_1">%d</xliff:g> pokusu, potom sa SIM karta natrvalo zablokuje. Podrobnosti vám poskytne operátor.</item>
+ <item quantity="other">SIM karta je deaktivovaná. Pokračujte zadaním kódu PUK. Zostáva vám <xliff:g id="_NUMBER_1">%d</xliff:g> pokusov, potom sa SIM karta natrvalo zablokuje. Podrobnosti vám poskytne operátor.</item>
+ <item quantity="one">SIM karta je deaktivovaná. Pokračujte zadaním kódu PUK. Zostáva vám <xliff:g id="_NUMBER_0">%d</xliff:g> pokus, potom sa SIM karta natrvalo zablokuje. Podrobnosti vám poskytne operátor.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index 9004a1e..cd53c6c 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>
@@ -148,4 +147,16 @@
<item quantity="other">Naprava ni bila odklenjena <xliff:g id="NUMBER_1">%d</xliff:g> ur. Potrdite geslo.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Ni prepoznano"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Vnesite kodo PIN kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskus.</item>
+ <item quantity="two">Vnesite kodo PIN kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskusa.</item>
+ <item quantity="few">Vnesite kodo PIN kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskuse.</item>
+ <item quantity="other">Vnesite kodo PIN kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskusov.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">Kartica SIM je zdaj onemogočena. Če želite nadaljevati, vnesite kodo PUK. Na voljo imate še <xliff:g id="_NUMBER_1">%d</xliff:g> poskus. Potem bo kartica SIM postala trajno neuporabna. Za podrobnosti se obrnite na operaterja.</item>
+ <item quantity="two">Kartica SIM je zdaj onemogočena. Če želite nadaljevati, vnesite kodo PUK. Na voljo imate še <xliff:g id="_NUMBER_1">%d</xliff:g> poskusa. Potem bo kartica SIM postala trajno neuporabna. Za podrobnosti se obrnite na operaterja.</item>
+ <item quantity="few">Kartica SIM je zdaj onemogočena. Če želite nadaljevati, vnesite kodo PUK. Na voljo imate še <xliff:g id="_NUMBER_1">%d</xliff:g> poskuse. Potem bo kartica SIM postala trajno neuporabna. Za podrobnosti se obrnite na operaterja.</item>
+ <item quantity="other">Kartica SIM je zdaj onemogočena. Če želite nadaljevati, vnesite kodo PUK. Na voljo imate še <xliff:g id="_NUMBER_1">%d</xliff:g> poskusov. Potem bo kartica SIM postala trajno neuporabna. Za podrobnosti se obrnite na operaterja.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index 2521b99..0a55795 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>
@@ -136,4 +135,12 @@
<item quantity="one">Pajisja nuk është shkyçur për <xliff:g id="NUMBER_0">%d</xliff:g> orë. Konfirmo fjalëkalimin.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Nuk njihet"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Fut kodin PIN të kartës SIM, të kanë mbetur edhe <xliff:g id="NUMBER_1">%d</xliff:g> tentativa.</item>
+ <item quantity="one">Fut kodin PIN të kartës SIM, të ka mbetur edhe <xliff:g id="NUMBER_0">%d</xliff:g> tentativë para se të kontaktosh me operatorin tënd celular për ta shkyçur pajisjen.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">Karta SIM tani është çaktivizuar. Fut kodin PUK për të vazhduar. Të kanë mbetur edhe <xliff:g id="_NUMBER_1">%d</xliff:g> përpjekje përpara se karta SIM të bëhet përgjithmonë e papërdorshme. Kontakto me operatorin për detaje.</item>
+ <item quantity="one">Karta SIM tani është çaktivizuar. Fut kodin PUK për të vazhduar. Të ka mbetur edhe <xliff:g id="_NUMBER_0">%d</xliff:g> përpjekje përpara se karta SIM të bëhet përgjithmonë e papërdorshme. Kontakto me operatorin për detaje.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index 9d06e00..08db0bd1 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -141,4 +141,14 @@
<item quantity="other">Нисте откључали уређај <xliff:g id="NUMBER_1">%d</xliff:g> сати. Потврдите лозинку.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Није препознат"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Унесите PIN за SIM. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај.</item>
+ <item quantity="few">Унесите PIN за SIM. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушаја.</item>
+ <item quantity="other">Унесите PIN за SIM. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушаја.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">SIM је сада онемогућен. Унесите PUK кôд да бисте наставили. Имате још <xliff:g id="_NUMBER_1">%d</xliff:g> покушај пре него што SIM постане трајно неупотребљив. Детаљне информације потражите од мобилног оператера.</item>
+ <item quantity="few">SIM је сада онемогућен. Унесите PUK кôд да бисте наставили. Имате још <xliff:g id="_NUMBER_1">%d</xliff:g> покушаја пре него што SIM постане трајно неупотребљив. Детаљне информације потражите од мобилног оператера.</item>
+ <item quantity="other">SIM је сада онемогућен. Унесите PUK кôд да бисте наставили. Имате још <xliff:g id="_NUMBER_1">%d</xliff:g> покушаја пре него што SIM постане трајно неупотребљив. Детаљне информације потражите од мобилног оператера.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index 03f2086..54a1d0d 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>
@@ -136,4 +135,12 @@
<item quantity="one">Enheten har inte låsts upp på <xliff:g id="NUMBER_0">%d</xliff:g> timme. Bekräfta lösenordet.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Identifierades inte"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Ange pinkod för SIM-kortet. <xliff:g id="NUMBER_1">%d</xliff:g> försök återstår.</item>
+ <item quantity="one">Ange pinkod för SIM-kortet. <xliff:g id="NUMBER_0">%d</xliff:g> försök återstår innan du måste kontakta operatören för att låsa upp enheten.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM-kortet är inaktiverat. Ange PUK-koden om du vill fortsätta. <xliff:g id="_NUMBER_1">%d</xliff:g> försök återstår innan SIM-kortet blir obrukbart. Kontakta operatören för mer information.</item>
+ <item quantity="one">SIM-kortet är inaktiverat. Ange PUK-koden om du vill fortsätta. <xliff:g id="_NUMBER_0">%d</xliff:g> försök återstår innan SIM-kortet blir obrukbart. Kontakta operatören för mer information.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index ff75819..7e85131 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -135,4 +135,12 @@
<item quantity="one">Hujafungua kifaa kwa saa <xliff:g id="NUMBER_0">%d</xliff:g>. Thibitisha nenosiri.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Haikutambua alama ya kidole"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Weka PIN ya SIM, umesalia na majaribio <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
+ <item quantity="one">PIN ya SIM uliyoweka si sahihi. Umesalia na jaribio <xliff:g id="NUMBER_0">%d</xliff:g> kabla ya kulazimika kuwasiliana na mtoa huduma wako ili afungue kifaa chako.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">Sasa SIM imefungwa. Weka msimbo wa PUK ili uendelee. Umesalia na majaribio <xliff:g id="_NUMBER_1">%d</xliff:g> kabla ya SIM kuacha kufanya kazi kabisa. Wasiliana na mtoa huduma kwa maelezo.</item>
+ <item quantity="one">Sasa SIM imefungwa. Weka msimbo wa PUK ili uendelee. Umesalia na jaribio <xliff:g id="_NUMBER_0">%d</xliff:g> kabla ya SIM kuacha kufanya kazi kabisa. Wasiliana na mtoa huduma kwa maelezo.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index 0ba941c..727ea5b 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -135,4 +135,6 @@
<item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> மணிநேரமாகச் சாதனம் திறக்கப்படவில்லை. கடவுச்சொல்லை உறுதிப்படுத்தவும்.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"அடையாளங்காண முடியவில்லை"</string>
+ <!-- no translation found for kg_password_default_pin_message (6203676909479972943) -->
+ <!-- no translation found for kg_password_default_puk_message (8744416410184198352) -->
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index 73f7094..ddc5928 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -135,4 +135,6 @@
<item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> గంట పాటు పరికరాన్ని అన్లాక్ చేయలేదు. పాస్వర్డ్ని నమోదు చేయండి.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"గుర్తించలేదు"</string>
+ <!-- no translation found for kg_password_default_pin_message (6203676909479972943) -->
+ <!-- no translation found for kg_password_default_puk_message (8744416410184198352) -->
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index 46d6ba8..aa33421 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>
@@ -136,4 +135,12 @@
<item quantity="one">ไม่มีการปลดล็อกอุปกรณ์มา <xliff:g id="NUMBER_0">%d</xliff:g> ชั่วโมงแล้ว ยืนยันรหัสผ่าน</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"ไม่รู้จัก"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">ป้อน PIN ของซิม คุณพยายามได้อีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง</item>
+ <item quantity="one">PIN ของซิมไม่ถูกต้อง คุณพยายามได้อีก <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งก่อนที่จะต้องติดต่อผู้ให้บริการเพื่อปลดล็อกอุปกรณ์</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">ซิมถูกปิดใช้งานในขณะนี้ โปรดป้อนรหัส PUK เพื่อทำต่อ คุณพยายามได้อีก <xliff:g id="_NUMBER_1">%d</xliff:g> ครั้งก่อนที่ซิมจะไม่สามารถใช้งานได้อย่างถาวร โปรดติดต่อสอบถามรายละเอียดจากผู้ให้บริการ</item>
+ <item quantity="one">ซิมถูกปิดใช้งานในขณะนี้ โปรดป้อนรหัส PUK เพื่อทำต่อ คุณพยายามได้อีก <xliff:g id="_NUMBER_0">%d</xliff:g> ครั้งก่อนที่ซิมจะไม่สามารถใช้งานได้อย่างถาวร โปรดติดต่อสอบถามรายละเอียดจากผู้ให้บริการ</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml
index 2998904..30657d4 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>
@@ -136,4 +135,12 @@
<item quantity="other">Hindi na-unlock ang device sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> na oras. Kumpirmahin ang password.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Hindi nakilala"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Ilagay ang PIN ng SIM, mayroon kang <xliff:g id="NUMBER_1">%d</xliff:g> natitirang pagsubok.</item>
+ <item quantity="other">Ilagay ang PIN ng SIM, mayroon kang <xliff:g id="NUMBER_1">%d</xliff:g> na natitirang pagsubok.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">Naka-disable na ang SIM. Ilagay ang PUK code upang magpatuloy. Mayroon kang <xliff:g id="_NUMBER_1">%d</xliff:g> natitirang pagsubok bago tuluyang hindi magamit ang SIM. Makipag-ugnayan sa carrier para sa mga detalye.</item>
+ <item quantity="other">Naka-disable na ang SIM. Ilagay ang PUK code upang magpatuloy. Mayroon kang <xliff:g id="_NUMBER_1">%d</xliff:g> na natitirang pagsubok bago tuluyang hindi magamit ang SIM. Makipag-ugnayan sa carrier para sa mga detalye.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index b80e4db..ca53dfb8 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -135,4 +135,12 @@
<item quantity="one">Cihazın kilidi son <xliff:g id="NUMBER_0">%d</xliff:g> saattir açılmadı. Şifreyi doğrulayın.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Tanınmadı"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">SIM PIN\'inizi girin. <xliff:g id="NUMBER_1">%d</xliff:g> deneme hakkınız kaldı.</item>
+ <item quantity="one">SIM PIN\'inizi girin. Cihazınızın kilidini açmak için operatörünüzle bağlantı kurmak zorunda kalmadan önce <xliff:g id="NUMBER_0">%d</xliff:g> deneme hakkınız kaldı.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM artık devre dışı. Devam etmek için PUK kodunu girin. SIM kalıcı olarak kullanım dışı kalmadan önce <xliff:g id="_NUMBER_1">%d</xliff:g> deneme hakkınız kaldı. Ayrıntılı bilgi için operatörünüzle iletişim kurun.</item>
+ <item quantity="one">SIM artık devre dışı. Devam etmek için PUK kodunu girin. SIM kalıcı olarak kullanım dışı kalmadan önce <xliff:g id="_NUMBER_0">%d</xliff:g> deneme hakkınız kaldı. Ayrıntılı bilgi için operatörünüzle iletişim kurun.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index 43d01b5..4b79744 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>
@@ -148,4 +147,16 @@
<item quantity="other">Ви не розблоковували пристрій <xliff:g id="NUMBER_1">%d</xliff:g> години. Підтвердьте пароль.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Не розпізнано"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Введіть PIN-код SIM-карти. Залишилася <xliff:g id="NUMBER_1">%d</xliff:g> спроба.</item>
+ <item quantity="few">Введіть PIN-код SIM-карти. Залишилося <xliff:g id="NUMBER_1">%d</xliff:g> спроби.</item>
+ <item quantity="many">Введіть PIN-код SIM-карти. Залишилося <xliff:g id="NUMBER_1">%d</xliff:g> спроб.</item>
+ <item quantity="other">Введіть PIN-код SIM-карти. Залишилося <xliff:g id="NUMBER_1">%d</xliff:g> спроби.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">SIM-карту заблоковано. Щоб продовжити, введіть PUK-код. Залишилася <xliff:g id="_NUMBER_1">%d</xliff:g> спроба. Після цього SIM-карту буде назавжди заблоковано. Щоб дізнатися більше, зверніться до свого оператора.</item>
+ <item quantity="few">SIM-карту заблоковано. Щоб продовжити, введіть PUK-код. Залишилося <xliff:g id="_NUMBER_1">%d</xliff:g> спроби. Після цього SIM-карту буде назавжди заблоковано. Щоб дізнатися більше, зверніться до свого оператора.</item>
+ <item quantity="many">SIM-карту заблоковано. Щоб продовжити, введіть PUK-код. Залишилося <xliff:g id="_NUMBER_1">%d</xliff:g> спроб. Після цього SIM-карту буде назавжди заблоковано. Щоб дізнатися більше, зверніться до свого оператора.</item>
+ <item quantity="other">SIM-карту заблоковано. Щоб продовжити, введіть PUK-код. Залишилося <xliff:g id="_NUMBER_1">%d</xliff:g> спроби. Після цього SIM-карту буде назавжди заблоковано. Щоб дізнатися більше, зверніться до свого оператора.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index 3bb59f0..5440a87 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -135,4 +135,6 @@
<item quantity="one">آلہ <xliff:g id="NUMBER_0">%d</xliff:g> گھنٹہ سے غیر مقفل نہیں کیا گیا۔ پاسورڈ کی توثیق کریں۔</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"تسلیم شدہ نہیں ہے"</string>
+ <!-- no translation found for kg_password_default_pin_message (6203676909479972943) -->
+ <!-- no translation found for kg_password_default_puk_message (8744416410184198352) -->
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index 699ad60..ee11cff 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -135,4 +135,12 @@
<item quantity="one">Qurilma <xliff:g id="NUMBER_0">%d</xliff:g> soatdan beri qulfdan chiqarilgani yo‘q. Parolni yana bir marta kiriting.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Barmoq izi aniqlanmadi"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">SIM PIN kodini kiriting, sizda <xliff:g id="NUMBER_1">%d</xliff:g> ta urinish bor.</item>
+ <item quantity="one">SIM PIN kodini kiriting, qurilmani qulfdan chiqarish uchun sizda <xliff:g id="NUMBER_0">%d</xliff:g> ta urinish bor.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM karta faolsizlantirildi. Davom etish uchun PUK kodni kiriting. Yana <xliff:g id="_NUMBER_1">%d</xliff:g> marta urinib ko‘rganingizdan keyin SIM kartadan umuman foydalanib bo‘lmaydi. Batafsil axborot olish uchun tarmoq operatoriga murojaat qiling.</item>
+ <item quantity="one">SIM karta faolsizlantirildi. Davom etish uchun PUK kodni kiriting. Yana <xliff:g id="_NUMBER_0">%d</xliff:g> marta urinib ko‘rganingizdan keyin SIM kartadan umuman foydalanib bo‘lmaydi. Batafsil axborot olish uchun tarmoq operatoriga murojaat qiling.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 6b32d3a..d20b87e 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>
@@ -136,4 +135,12 @@
<item quantity="one">Thiết bị đã không được mở khóa trong <xliff:g id="NUMBER_0">%d</xliff:g> giờ. Xác nhận mật khẩu.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Không nhận dạng được"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">Hãy nhập mã PIN của SIM, bạn còn <xliff:g id="NUMBER_1">%d</xliff:g> lần thử.</item>
+ <item quantity="one">Hãy nhập mã PIN của SIM, bạn còn <xliff:g id="NUMBER_0">%d</xliff:g> lần thử trước khi bạn phải liên hệ với nhà cung cấp dịch vụ để mở khóa thiết bị của mình.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM hiện đã bị tắt. Hãy nhập mã PUK để tiếp tục. Bạn còn <xliff:g id="_NUMBER_1">%d</xliff:g> lần thử trước khi SIM vĩnh viễn không sử dụng được. Hãy liên hệ với nhà cung cấp dịch vụ để biết chi tiết.</item>
+ <item quantity="one">SIM hiện đã bị tắt. Hãy nhập mã PUK để tiếp tục. Bạn còn <xliff:g id="_NUMBER_0">%d</xliff:g> lần thử trước khi SIM vĩnh viễn không thể sử dụng được. Hãy liên hệ với nhà cung cấp dịch vụ để biết chi tiết.</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index d523c20..8ee5812 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -135,4 +135,12 @@
<item quantity="one">设备已保持锁定状态达 <xliff:g id="NUMBER_0">%d</xliff:g> 小时。请确认密码。</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"无法识别"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">请输入 SIM 卡 PIN 码,您还可以尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
+ <item quantity="one">请输入 SIM 卡 PIN 码,您还可以尝试 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍不正确,则需要联系运营商帮您解锁设备。</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM 卡现已停用,请输入 PUK 码继续使用。您还可以尝试 <xliff:g id="_NUMBER_1">%d</xliff:g> 次。如果仍不正确,该 SIM 卡将永远无法使用。有关详情,请联系您的运营商。</item>
+ <item quantity="one">SIM 卡现已停用,请输入 PUK 码继续使用。您还可以尝试 <xliff:g id="_NUMBER_0">%d</xliff:g> 次。如果仍不正确,该 SIM 卡将永远无法使用。有关详情,请联系您的运营商。</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index 1c159ca..5b0754e 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>
@@ -136,4 +135,12 @@
<item quantity="one">裝置在過去 <xliff:g id="NUMBER_0">%d</xliff:g> 小時內未有解鎖,請確認密碼。</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"未能識別"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">輸入 SIM 卡的 PIN,您還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
+ <item quantity="one">輸入 SIM 卡的 PIN,您還可以再試 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍然輸入錯誤,您必須聯絡流動網絡供應商解鎖您的裝置。</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM 卡已停用。請輸入 PUK 碼以繼續進行。您還可以再試 <xliff:g id="_NUMBER_1">%d</xliff:g> 次。如果仍然輸入錯誤,SIM 卡將永久無法使用。詳情請與流動網絡供應商聯絡。</item>
+ <item quantity="one">SIM 卡已停用。請輸入 PUK 碼以繼續進行。您還可以再試 <xliff:g id="_NUMBER_0">%d</xliff:g> 次。如果仍然輸入錯誤,SIM 卡將永久無法使用。詳情請與流動網絡供應商聯絡。</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index a1d072a..45ab593 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>
@@ -136,4 +135,12 @@
<item quantity="one">裝置已有 <xliff:g id="NUMBER_0">%d</xliff:g> 小時未解鎖。請確認密碼。</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"無法識別"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="other">請輸入 SIM 卡的 PIN 碼,你還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
+ <item quantity="one">請輸入 SIM 卡的 PIN 碼,你還可以再試 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍然失敗,就必須請電信業者為裝置解鎖。</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="other">SIM 卡現在已遭停用。請輸入 PUK 碼以繼續進行。你還可以再試 <xliff:g id="_NUMBER_1">%d</xliff:g> 次,如果仍然失敗,SIM 卡將永久無法使用。詳情請與電信業者聯絡。</item>
+ <item quantity="one">SIM 卡現在已遭停用。請輸入 PUK 碼以繼續進行。你還可以再試 <xliff:g id="_NUMBER_0">%d</xliff:g> 次,如果仍然失敗,SIM 卡將永久無法使用。詳情請與電信業者聯絡。</item>
+ </plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index 4602237..2329320 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>
@@ -136,4 +135,12 @@
<item quantity="other">Idivayisi ayikavulwa ngamahora angu-<xliff:g id="NUMBER_1">%d</xliff:g>. Qinisekisa iphasiwedi.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Akubonwa"</string>
+ <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+ <item quantity="one">Faka i-PIN ye-SIM, unemizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g> esele.</item>
+ <item quantity="other">Faka i-PIN ye-SIM, unemizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g> esele.</item>
+ </plurals>
+ <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+ <item quantity="one">I-SIM manje ikhutshaziwe. Faka ikhodi ye-PUK ukuze uqhubeke. Unemizamo engu-<xliff:g id="_NUMBER_1">%d</xliff:g> esele ngaphambi kokuthi i-SIM ingasebenziseki unaphakade. Xhumana nenkampani yenethiwekhi ngemininingwane.</item>
+ <item quantity="other">I-SIM manje ikhutshaziwe. Faka ikhodi ye-PUK ukuze uqhubeke. Unemizamo engu-<xliff:g id="_NUMBER_1">%d</xliff:g> esele ngaphambi kokuthi i-SIM ingasebenziseki unaphakade. Xhumana nenkampani yenethiwekhi ngemininingwane.</item>
+ </plurals>
</resources>
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/output_chooser.xml b/packages/SystemUI/res/layout/output_chooser.xml
new file mode 100644
index 0000000..22c3bcf
--- /dev/null
+++ b/packages/SystemUI/res/layout/output_chooser.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.
+-->
+<!-- extends FrameLayout -->
+<com.android.systemui.volume.OutputChooserLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:sysui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/output_chooser"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="20dp" >
+
+ <com.android.systemui.qs.AutoSizingList
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ sysui:itemHeight="@dimen/qs_detail_item_height"
+ style="@style/AutoSizingList"/>
+
+ <LinearLayout
+ android:id="@android:id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="56dp"
+ android:layout_height="56dp"
+ android:tint="?android:attr/textColorSecondary" />
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailEmpty"/>
+ </LinearLayout>
+</com.android.systemui.volume.OutputChooserLayout>
diff --git a/packages/SystemUI/res/layout/output_chooser_item.xml b/packages/SystemUI/res/layout/output_chooser_item.xml
new file mode 100644
index 0000000..ed7df4b
--- /dev/null
+++ b/packages/SystemUI/res/layout/output_chooser_item.xml
@@ -0,0 +1,71 @@
+<?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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/qs_detail_item_height"
+ android:background="@drawable/btn_borderless_rect"
+ android:clickable="true"
+ android:focusable="true"
+ android:gravity="center_vertical"
+ android:orientation="horizontal" >
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="@dimen/qs_detail_item_icon_width"
+ android:layout_height="@dimen/qs_detail_item_icon_size"
+ android:layout_marginStart="@dimen/qs_detail_item_icon_marginStart"
+ android:layout_marginEnd="@dimen/qs_detail_item_icon_marginEnd"
+ android:tint="?android:attr/textColorPrimary"/>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_weight="1"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textDirection="locale"
+ android:ellipsize="end"
+ android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary" />
+
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textDirection="locale"
+ android:layout_marginTop="2dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailItemSecondary" />
+ </LinearLayout>
+
+ <ImageView
+ android:id="@android:id/icon2"
+ style="@style/QSBorderlessButton"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="30dp"
+ android:clickable="true"
+ android:focusable="true"
+ android:scaleType="center"
+ android:contentDescription="@*android:string/media_route_controller_disconnect"
+ android:tint="?android:attr/textColorPrimary" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index fac254a..f0d2346 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,20 @@
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:layout_toStartOf="@id/expand"
+ android:clipChildren="false"
+ android:clipToPadding="false"
android:orientation="vertical" >
<LinearLayout
@@ -42,7 +44,103 @@
android:orientation="vertical" >
<!-- volume rows added and removed here! :-) -->
</LinearLayout>
- </LinearLayout>
+
+ </LinearLayout>
+ <LinearLayout
+ android:id="@+id/expand"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginEnd="@dimen/volume_expander_margin_end" >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:textAppearance="@style/TextAppearance.Volume.Header" />
+ <com.android.keyguard.AlphaOptimizedImageButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/volume_expand_button"
+ style="@style/VolumeButtons"
+ android:layout_width="@dimen/volume_button_size"
+ android:layout_height="@dimen/volume_button_size"
+ android:clickable="true"
+ android:soundEffectsEnabled="false"
+ android:src="@drawable/ic_volume_expand_animation"
+ android:background="@drawable/ripple_drawable"
+ tools:ignore="RtlHardcoded" />
+ </LinearLayout>
+ <RelativeLayout
+ android:id="@+id/footer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:layout_below="@id/volume_dialog_content"
+ android:layout_margin="10dp">
+ <!-- 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_toStartOf="@id/output_chooser"
+ 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/ring_toggle_title"
+ 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>
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/output_chooser"
+ style="@style/VolumeButtons"
+ android:background="?android:selectableItemBackgroundBorderless"
+ android:layout_width="@dimen/volume_button_size"
+ android:layout_height="@dimen/volume_button_size"
+ android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true"
+ android:src="@drawable/ic_settings_bluetooth"
+ android:soundEffectsEnabled="false" />
+ </RelativeLayout>
</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..b9a228f 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Dubbele multitoonfrekwensie"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Toeganklikheid"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Lui"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibreer"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Demp"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tik om te ontdemp."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tik om op vibreer te stel. Toeganklikheidsdienste kan dalk gedemp wees."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Tik om te demp. Toeganklikheidsdienste kan dalk gedemp wees."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Kitsprogramme"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Kitsprogramme hoef nie geïnstalleer te word nie."</string>
<string name="app_info" msgid="6856026610594615344">"Programinligting"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Gaan na web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Gaan na blaaier"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobiele data"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is af"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth is af"</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..961ac45 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"ብሉቱዝ"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"ድርብ ባለ በርካታ ቅላጼ ድግምግሞሽ"</string>
<string name="stream_accessibility" msgid="301136219144385106">"ተደራሽነት"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"ጥሪ"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"ንዘር"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"ድምጸ-ከል አድርግ"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s። ወደ ንዝረት ለማቀናበር መታ ያድርጉ። የተደራሽነት አገልግሎቶች ድምጸ-ከል ሊደረግባቸው ይችላል።"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ። የተደራሽነት አገልግሎቶች ድምጸ-ከል ሊደረግባቸው ይችላል።"</string>
@@ -582,8 +583,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 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"ወደ አሳሽ ሂድ"</string>
<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-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index d642118..8437705 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>
@@ -502,6 +500,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"بلوتوث"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"تردد ثنائي متعدد النغمات"</string>
<string name="stream_accessibility" msgid="301136219144385106">"إمكانية الوصول"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"استصدار رنين"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"اهتزاز"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"كتم الصوت"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. انقر لإلغاء التجاهل."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. انقر للتعيين على الاهتزاز. قد يتم تجاهل خدمات إمكانية الوصول."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. انقر للتجاهل. قد يتم تجاهل خدمات إمكانية الوصول."</string>
@@ -606,8 +607,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>
@@ -782,7 +783,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"الانتقال إلى المتصفح"</string>
<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-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..098b1cd 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Çoxsaylı ton olan ikili tezlik"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Münasiblik"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Zəng"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrasiya"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Susdurun"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Səsli etmək üçün tıklayın."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Vibrasiyanı ayarlamaq üçün tıklayın. Əlçatımlılıq xidmətləri səssiz edilmiş ola bilər."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Səssiz etmək üçün tıklayın. Əlçatımlılıq xidmətləri səssiz edilmiş ola bilər."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Ani Tətbiqlər"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Ani tətbiqlər quraşdırma tələb etmir."</string>
<string name="app_info" msgid="6856026610594615344">"Tətbiq məlumatı"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Vebə keçin"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Brauzerə daxil edin"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobil data"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi deaktivdir"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth deaktivdir"</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..ae3854f 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Višestruka frekvencija dualnog tona"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Pristupačnost"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Aktiviraj zvono"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibriraj"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Isključi zvuk"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Dodirnite da biste uključili zvuk."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Dodirnite da biste podesili na vibraciju. Zvuk usluga pristupačnosti će možda biti isključen."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Dodirnite da biste isključili zvuk. Zvuk usluga pristupačnosti će možda biti isključen."</string>
@@ -588,8 +589,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>
@@ -764,7 +765,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant aplikacije"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Instant aplikacije ne zahtevaju instalaciju."</string>
<string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Idi na veb"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Idi na pregledač"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobilni podaci"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi je isključen"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth je isključen"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index e2ee4ea..3c9f83a 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>
@@ -506,6 +498,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Двухтанальны шматчастотны"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Спецыяльныя магчымасці"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Званок"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Вібрацыя"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Гук выключаны"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Дакраніцеся, каб уключыць гук."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Дакраніцеся, каб уключыць вібрацыю. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Дакраніцеся, каб адключыць гук. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
@@ -602,8 +597,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>
@@ -778,7 +773,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"Перайсці ў браўзер"</string>
<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-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..1cd4c91 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Тонално набиране"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Достъпност"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Позвъняване"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Вибриране"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Без звук"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Докоснете, за да включите отново звука."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Докоснете, за да зададете вибриране. Възможно е звукът на услугите за достъпност да бъде заглушен."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Докоснете, за да заглушите звука. Възможно е звукът на услугите за достъпност да бъде заглушен."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"Към браузъра"</string>
<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-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 581ac73..c823525 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>
@@ -494,6 +492,12 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"ব্লুটুথ"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"ডুয়েল মাল্টি টোন ফ্রিকোয়েন্সি"</string>
<string name="stream_accessibility" msgid="301136219144385106">"অ্যাক্সেসযোগ্যতা"</string>
+ <!-- no translation found for volume_ringer_status_normal (4273142424125855384) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_vibrate (1825615171021346557) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_silent (6896394161022916369) -->
+ <skip />
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s। সশব্দ করতে আলতো চাপুন।"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s। কম্পন এ সেট করতে আলতো চাপুন। অ্যাক্সেসযোগ্যতার পরিষেবাগুলিকে নিঃশব্দ করা হতে পারে।"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s। নিঃশব্দ করতে আলতো চাপুন। অ্যাক্সেসযোগ্যতার পরিষেবাগুলিকে নিঃশব্দ করা হতে পারে।"</string>
@@ -582,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>
@@ -732,10 +736,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 +762,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"ব্রাউজারে যান"</string>
<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..f09bb1f 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Dvostruka višemelodijska frekvencija"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Pristupačnost"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Zvono"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibriranje"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Isključi zvuk"</string>
<!-- String.format failed for translation -->
<!-- no translation found for volume_stream_content_description_unmute (4436631538779230857) -->
<skip />
@@ -505,7 +506,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 +529,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 +591,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 +767,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"Idi na preglednik"</string>
<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..e87bb45 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Marcatge per tons"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Accessibilitat"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Fes sonar"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibra"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Silencia"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toca per activar el so."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toca per activar la vibració. Pot ser que els serveis d\'accessibilitat se silenciïn."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Toca per silenciar el so. Pot ser que els serveis d\'accessibilitat se silenciïn."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Aplicacions instantànies"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"No cal instal·lar les aplicacions instantànies."</string>
<string name="app_info" msgid="6856026610594615344">"Informació de l\'aplicació"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Ves al web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Ves al navegador"</string>
<string name="mobile_data" msgid="7094582042819250762">"Dades mòbils"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"La Wi-Fi està desactivada"</string>
<string name="bt_is_off" msgid="2640685272289706392">"El Bluetooth està desactivat"</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..e0e14a1 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>
@@ -500,6 +498,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Tónová volba"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Přístupnost"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Vyzvánění"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrace"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Ztlumení"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Klepnutím zapnete zvuk."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Klepnutím aktivujete režim vibrací. Služby přístupnosti mohou být ztlumeny."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Klepnutím vypnete zvuk. Služby přístupnosti mohou být ztlumeny."</string>
@@ -596,8 +597,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 +648,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>
@@ -772,7 +773,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Okamžité aplikace"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Okamžité aplikace není třeba instalovat."</string>
<string name="app_info" msgid="6856026610594615344">"O aplikaci"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Přejít na web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Přejít do prohlížeče"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobilní data"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi je vypnuta"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth je vypnuto"</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..fb886fc 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Tonesignalfrekvens (DTMF)"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Hjælpefunktioner"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Ring"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibration"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Slå lyden fra"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tryk for at slå lyden til."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tryk for at konfigurere til at vibrere. Tilgængelighedstjenester kan blive deaktiveret."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Tryk for at slå lyden fra. Lyden i tilgængelighedstjenester kan blive slået fra."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Instant apps kræver ingen installation."</string>
<string name="app_info" msgid="6856026610594615344">"Appinfo"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Gå til website"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Gå til en browser"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobildata"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi er slået fra"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth er slået fra"</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..feb7064 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>
@@ -498,6 +496,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Doppelton-Mehrfrequenz"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Bedienungshilfen"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Klingeln lassen"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrieren"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Stummschalten"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Zum Aufheben der Stummschaltung tippen."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tippen, um Vibrieren festzulegen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Zum Stummschalten tippen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
@@ -586,8 +587,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>
@@ -762,7 +763,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant-Apps"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Bei Instant-Apps ist keine vorherige Installation erforderlich."</string>
<string name="app_info" msgid="6856026610594615344">"App-Informationen"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Web aufrufen"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Browser öffnen"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobile Daten"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"WLAN ist deaktiviert"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth ist deaktiviert"</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..1fe9010 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Πολυσυχνότητα διπλού τόνου"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Προσβασιμότητα"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Κουδούνισμα"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Δόνηση"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Σίγαση"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Πατήστε για κατάργηση σίγασης."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Πατήστε για ενεργοποιήσετε τη δόνηση. Οι υπηρεσίες προσβασιμότητας ενδέχεται να τεθούν σε σίγαση."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Πατήστε για σίγαση. Οι υπηρεσίες προσβασιμότητας ενδέχεται να τεθούν σε σίγαση."</string>
@@ -582,8 +583,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 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant Εφαρμογές"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Οι Instant Εφαρμογές δεν απαιτούν εγκατάσταση."</string>
<string name="app_info" msgid="6856026610594615344">"Πληροφορίες εφαρμογής"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Μετάβαση στον ιστό"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Μετάβ. σε πρόγ. περ."</string>
<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-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..4af3f59 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Multifrecuencia de tono doble"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Accesibilidad"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Hacer sonar"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrar"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Silenciar"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Presiona para dejar de silenciar."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Presiona para establecer el modo vibración. Es posible que los servicios de accesibilidad estén silenciados."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Presiona para silenciar. Es posible que los servicios de accesibilidad estén silenciados."</string>
@@ -584,8 +585,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>
@@ -760,7 +761,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Apps instantáneas"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Las Apps instantáneas no requieren instalación."</string>
<string name="app_info" msgid="6856026610594615344">"Información de apps"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Ir a la Web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Ir al navegador"</string>
<string name="mobile_data" msgid="7094582042819250762">"Datos móviles"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi desactivado"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth desactivado"</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..14c2818 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Multifrecuencia de tono dual"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Accesibilidad"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Hacer sonar"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrar"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Silenciar"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toca para activar el sonido."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toca para poner el dispositivo en vibración. Los servicios de accesibilidad pueden silenciarse."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Toca para silenciar. Los servicios de accesibilidad pueden silenciarse."</string>
@@ -584,8 +585,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>
@@ -760,7 +761,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Aplicaciones Instantáneas"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"No es necesario instalar las Aplicaciones Instantáneas."</string>
<string name="app_info" msgid="6856026610594615344">"Información de la aplicación"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Ir a la Web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Ir al navegador"</string>
<string name="mobile_data" msgid="7094582042819250762">"Datos móviles"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi desactivado"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth desactivado"</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..27e4920 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Kaks mitme tooniga sagedust"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Juurdepääsetavus"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Helisemine"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibreerimine"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Vaigistatud"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Puudutage vaigistuse tühistamiseks."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Puudutage värinarežiimi määramiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Puudutage vaigistamiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
@@ -584,8 +585,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>
@@ -760,7 +761,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Installimata avatavad rakendused"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Installimata avatavaid rakendusi pole vaja installida."</string>
<string name="app_info" msgid="6856026610594615344">"Rakenduse teave"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Avage veebis"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Ava brauser"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobiilne andmeside"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"WiFi on välja lülitatud"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth on välja lülitatud"</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..5d4181e 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth konexioa"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Tonu anitzeko maiztasun duala"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Erabilerraztasuna"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Jo tonua"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Dardara"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Ez jo tonua"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Sakatu audioa aktibatzeko."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Sakatu dardara ezartzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Sakatu audioa desaktibatzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
@@ -584,8 +585,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>
@@ -760,7 +761,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Zuzeneko aplikazioak"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Zuzeneko aplikazioak ez dira instalatu behar."</string>
<string name="app_info" msgid="6856026610594615344">"Aplikazioari buruzko informazioa"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Joan sarera"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Joan arakatzailera"</string>
<string name="mobile_data" msgid="7094582042819250762">"Datu mugikorrak"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi konexioa desaktibatuta dago"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth konexioa desaktibatuta dago"</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..9360c1d 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"بلوتوث"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"فرکانس دوتایی چند نوایی"</string>
<string name="stream_accessibility" msgid="301136219144385106">"دسترسپذیری"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"زنگ زدن"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"لرزش"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"بیصدا"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. برای باصدا کردن ضربه بزنید."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. برای تنظیم روی لرزش ضربه بزنید. ممکن است سرویسهای دسترسپذیری بیصدا شوند."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. برای بیصدا کردن ضربه بزنید. ممکن است سرویسهای دسترسپذیری بیصدا شوند."</string>
@@ -582,8 +583,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 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"رفتن به مرورگر"</string>
<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..864f8d0 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>
@@ -500,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Äänitaajuusvalinta"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Esteettömyys"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Soittoääni"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Värinä"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Äänetön"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Poista mykistys koskettamalla."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Siirry värinätilaan koskettamalla. Myös esteettömyyspalvelut saattavat mykistyä."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Mykistä koskettamalla. Myös esteettömyyspalvelut saattavat mykistyä."</string>
@@ -588,8 +583,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>
@@ -764,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Pikasovelluksia ei tarvitse asentaa."</string>
<string name="app_info" msgid="6856026610594615344">"Sovelluksen tiedot"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Avaa verkossa"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Siirry selaimeen"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobiilitiedonsiirto"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi on pois käytöstä"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth ei ole käytössä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 6e1feea..5c4394b 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Fréquence double multi ton"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Accessibilité"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Sonnerie"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibration"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Sonnerie désactivée"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Touchez pour réactiver le son."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Touchez pour activer les vibrations. Il est possible de couper le son des services d\'accessibilité."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Touchez pour couper le son. Il est possible de couper le son des services d\'accessibilité."</string>
@@ -584,8 +585,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>
@@ -760,7 +761,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Applications instantanées"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Les applications instantanées ne nécessitent pas d\'installation."</string>
<string name="app_info" msgid="6856026610594615344">"Détails de l\'application"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Accéder au Web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Ouvrir le navigateur"</string>
<string name="mobile_data" msgid="7094582042819250762">"Données cellulaires"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Le Wi-Fi est désactivé"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Le Bluetooth est désactivé"</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..21952ae 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"DTMF"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Accessibilité"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Sonnerie"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibreur"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Silencieux"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Appuyez pour ne plus ignorer."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Appuyez pour mettre en mode vibreur. Vous pouvez ignorer les services d\'accessibilité."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Appuyez pour ignorer. Vous pouvez ignorer les services d\'accessibilité."</string>
@@ -584,8 +585,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>
@@ -760,7 +761,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Applis instantanées"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Les applis instantanées ne nécessitent pas d\'installation."</string>
<string name="app_info" msgid="6856026610594615344">"Infos sur l\'appli"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Accéder au site Web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Accéder au navigateur"</string>
<string name="mobile_data" msgid="7094582042819250762">"Données mobiles"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi désactivé"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth désactivé"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 94c525a..a3d580b 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>
@@ -502,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Multifrecuencia de dobre ton"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Accesibilidade"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Facer soar"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrar"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Silenciar"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toca para activar o son."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toca para establecer a vibración. Pódense silenciar os servizos de accesibilidade."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Toca para silenciar. Pódense silenciar os servizos de accesibilidade."</string>
@@ -590,8 +585,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>
@@ -766,7 +761,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Aplicacións instantáneas"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"As aplicacións instantáneas non precisan instalación."</string>
<string name="app_info" msgid="6856026610594615344">"Info. da aplicación"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Acceder á web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Ir ao navegador"</string>
<string name="mobile_data" msgid="7094582042819250762">"Datos móbiles"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"A wifi está desactivada"</string>
<string name="bt_is_off" msgid="2640685272289706392">"O Bluetooth está desactivado"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index b13011a..83f7896 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/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>
@@ -500,6 +492,12 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"બ્લૂટૂથ"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"દ્વિ બહુ ટોન આવર્તન"</string>
<string name="stream_accessibility" msgid="301136219144385106">"ઍક્સેસિબિલિટી"</string>
+ <!-- no translation found for volume_ringer_status_normal (4273142424125855384) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_vibrate (1825615171021346557) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_silent (6896394161022916369) -->
+ <skip />
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. અનમ્યૂટ કરવા માટે ટૅપ કરો."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. વાઇબ્રેટ પર સેટ કરવા માટે ટૅપ કરો. ઍક્સેસિબિલિટી સેવાઓ મ્યૂટ કરવામાં આવી શકે છે."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. મ્યૂટ કરવા માટે ટૅપ કરો. ઍક્સેસિબિલિટી સેવાઓ મ્યૂટ કરવામાં આવી શકે છે."</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">"Home"</string>
@@ -764,7 +762,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"બ્રાઉઝર પર જાઓ"</string>
<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-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index dd1f729..e7fc696 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"ब्लूटूथ"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"दोहरी बहु टोन आवृत्ति"</string>
<string name="stream_accessibility" msgid="301136219144385106">"सुलभता"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"आवाज़ चालू है"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"कंपन (वाइब्रेशन)"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"आवाज़ बंद है"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. अनम्यूट करने के लिए टैप करें."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. कंपन पर सेट करने के लिए टैप करें. सुलभता सेवाएं म्यूट हो सकती हैं."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. म्यूट करने के लिए टैप करें. सुलभता सेवाएं म्यूट हो सकती हैं."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"ब्राउज़र पर जाएं"</string>
<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-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..88f5097 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"DTMF"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Pristupačnost"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Zvonjenje"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibriranje"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Zvuk je isključen"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Dodirnite da biste uključili zvuk."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Dodirnite da biste postavili na vibraciju. Usluge pristupačnosti možda neće imati zvuk."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Dodirnite da biste isključili zvuk. Usluge pristupačnosti možda neće imati zvuk."</string>
@@ -588,8 +589,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>
@@ -764,7 +765,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant aplikacije"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Instant aplikacije nije potrebno instalirati."</string>
<string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Prijeđi na web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Otvori preglednik"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobilni podaci"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi je isključen"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth je isključen"</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..e81df8f 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Kéthangú többfrekvenciás jelzésátvitel (DTMF)"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Kisegítő lehetőségek"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Csörgés"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Rezgés"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Néma"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Koppintson a némítás megszüntetéséhez."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Koppintson a rezgés beállításához. Előfordulhat, hogy a kisegítő lehetőségek szolgáltatásai le vannak némítva."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Koppintson a némításhoz. Előfordulhat, hogy a kisegítő lehetőségek szolgáltatásai le vannak némítva."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Azonnali alkalmazások"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Az azonnali alkalmazásokat nem kell telepíteni."</string>
<string name="app_info" msgid="6856026610594615344">"Alkalmazásinformáció"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Tovább az internetre"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Ugrás a böngészőbe"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobiladatok"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"A Wi-Fi ki van kapcsolva"</string>
<string name="bt_is_off" msgid="2640685272289706392">"A Bluetooth ki van kapcsolva"</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..2994b9b 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Կրկնակի բազմերանգ հաճախականություն"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Մատչելիություն"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Սովորական"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Թրթռազանգ"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Անձայն"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s: Հպեք՝ ձայնը միացնելու համար:"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s: Հպեք՝ թրթռումը միացնելու համար: Մատչելիության ծառայությունների ձայնը կարող է անջատվել:"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s: Հպեք՝ ձայնն անջատելու համար: Մատչելիության ծառայությունների ձայնը կարող է անջատվել:"</string>
@@ -582,8 +583,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 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"Անցնել դիտարկիչ"</string>
<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-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..f8604e3 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Frekuensi multinada ganda"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Aksesibilitas"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Dering"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Getar"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Nonaktifkan"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Ketuk untuk menyuarakan."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Ketuk untuk menyetel agar bergetar. Layanan aksesibilitas mungkin dibisukan."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Ketuk untuk membisukan. Layanan aksesibilitas mungkin dibisukan."</string>
@@ -571,7 +572,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 +583,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 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"Buka browser"</string>
<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..1efc249 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Tvítóna fjöltíðni"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Aðgengi"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Hringing"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Titringur"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Hljóð af"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Ýttu til að hætta að þagga."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Ýttu til að stilla á titring. Hugsanlega verður slökkt á hljóði aðgengisþjónustu."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Ýttu til að þagga. Hugsanlega verður slökkt á hljóði aðgengisþjónustu."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Skyndiforrit"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Skyndiforrit þurfa ekki uppsetningu."</string>
<string name="app_info" msgid="6856026610594615344">"Forritsupplýsingar"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Fara á vefinn"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Opna vafra"</string>
<string name="mobile_data" msgid="7094582042819250762">"Farsímagögn"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Slökkt á Wi-Fi"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Slökkt á Bluetooth"</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..c15e4b6 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Frequenza multipla dual tone"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Accessibilità"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Suoneria"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrazione"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Disattiva audio"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tocca per riattivare l\'audio."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tocca per attivare la vibrazione. L\'audio dei servizi di accessibilità può essere disattivato."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Tocca per disattivare l\'audio. L\'audio dei servizi di accessibilità può essere disattivato."</string>
@@ -584,8 +585,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>
@@ -760,7 +761,7 @@
<string name="instant_apps" msgid="6647570248119804907">"App istantanee"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Le app istantanee non richiedono l\'installazione."</string>
<string name="app_info" msgid="6856026610594615344">"Informazioni app"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Vai sul Web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Vai al browser"</string>
<string name="mobile_data" msgid="7094582042819250762">"Dati mobili"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi disattivato"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth non attivo"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index dcef8c6..2927116 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>
@@ -504,6 +496,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"טון זוגי מרובה תדרים (DTMF)"</string>
<string name="stream_accessibility" msgid="301136219144385106">"נגישות"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"צלצול"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"רטט"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"השתקה"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. הקש כדי לבטל את ההשתקה."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. הקש כדי להגדיר רטט. ייתכן ששירותי הנגישות מושתקים."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. הקש כדי להשתיק. ייתכן ששירותי הנגישות מושתקים."</string>
@@ -600,8 +595,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>
@@ -776,7 +771,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"מעבר אל הדפדפן"</string>
<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-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..38622c9 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"デュアルトーン マルチ周波数"</string>
<string name="stream_accessibility" msgid="301136219144385106">"ユーザー補助機能"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"着信音"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"バイブレーション"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"ミュート"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s。タップしてミュートを解除します。"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s。タップしてバイブレーションに設定します。ユーザー補助機能サービスがミュートされる場合があります。"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s。タップしてミュートします。ユーザー補助機能サービスがミュートされる場合があります。"</string>
@@ -584,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>
@@ -760,7 +761,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Instant Apps はインストールせずに利用できます。"</string>
<string name="app_info" msgid="6856026610594615344">"アプリ情報"</string>
- <string name="go_to_web" msgid="1106022723459948514">"ウェブページを開く"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"ブラウザに移動"</string>
<string name="mobile_data" msgid="7094582042819250762">"モバイルデータ"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi は OFF です"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth は OFF です"</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..933a5e3 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"ტონალური აკრეფა"</string>
<string name="stream_accessibility" msgid="301136219144385106">"მარტივი წვდომა"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"დარეკვა"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"ვიბრაცია"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"დადუმება"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. შეეხეთ დადუმების გასაუქმებლად."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. შეეხეთ ვიბრაციაზე დასაყენებლად. შეიძლება დადუმდეს მარტივი წვდომის სერვისებიც."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. შეეხეთ დასადუმებლად. შეიძლება დადუმდეს მარტივი წვდომის სერვისებიც."</string>
@@ -582,8 +583,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 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"ბრაუზერზე გადასვლა"</string>
<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..3f36c72 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Қос үнді көп жиілік"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Арнайы мүмкіндіктер"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Шылдырлау"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Діріл"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Дыбысын өшіру"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Дыбысын қосу үшін түртіңіз."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Діріл режимін орнату үшін түртіңіз. Арнайы мүмкіндік қызметтерінің дыбысы өшуі мүмкін."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Дыбысын өшіру үшін түртіңіз. Арнайы мүмкіндік қызметтерінің дыбысы өшуі мүмкін."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Лездік қолданбаларды орнатудың қажеті жоқ."</string>
<string name="app_info" msgid="6856026610594615344">"Қолданба ақпараты"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Вебке өту"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Браузерге өту"</string>
<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-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..1d5d7d4 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"ប៊្លូធូស"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"ហ្វ្រេកង់ពហុសំឡេងទ្វេ"</string>
<string name="stream_accessibility" msgid="301136219144385106">"ភាពងាយស្រួល"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"រោទ៍"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"ញ័រ"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"បិទ"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s។ ប៉ះដើម្បីបើកសំឡេង។"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s។ ប៉ះដើម្បីកំណត់ឲ្យញ័រ។ សេវាកម្មលទ្ធភាពប្រើប្រាស់អាចនឹងត្រូវបានបិទសំឡេង។"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s។ ប៉ះដើម្បីបិទសំឡេង។ សេវាកម្មលទ្ធភាពប្រើប្រាស់អាចនឹងត្រូវបានបិទសំឡេង។"</string>
@@ -582,8 +583,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 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"ចូលទៅកម្មវិធីរុករកតាមអ៊ីនធឺណិត"</string>
<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-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 7ba785b..b2e9d8f 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>
@@ -500,6 +492,12 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"ಬ್ಲೂಟೂತ್"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"ಡ್ಯುಯಲ್ ಬಹು ಟೋನ್ ಆವರ್ತನೆ"</string>
<string name="stream_accessibility" msgid="301136219144385106">"ಪ್ರವೇಶಿಸುವಿಕೆ"</string>
+ <!-- no translation found for volume_ringer_status_normal (4273142424125855384) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_vibrate (1825615171021346557) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_silent (6896394161022916369) -->
+ <skip />
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. ಅನ್ಮ್ಯೂಟ್ ಮಾಡುವುದಕ್ಕಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. ಕಂಪನಕ್ಕೆ ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಪ್ರವೇಶಿಸುವಿಕೆ ಸೇವೆಗಳನ್ನು ಮ್ಯೂಟ್ ಮಾಡಬಹುದು."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಪ್ರವೇಶಿಸುವಿಕೆ ಸೇವೆಗಳನ್ನು ಮ್ಯೂಟ್ ಮಾಡಬಹುದು."</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">"Home"</string>
@@ -764,7 +762,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"ಬ್ರೌಸರ್ಗೆ ಹೋಗಿ"</string>
<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-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..83018be 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"블루투스"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"듀얼 멀티 톤 주파수"</string>
<string name="stream_accessibility" msgid="301136219144385106">"접근성"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"벨소리"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"진동"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"음소거"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. 탭하여 음소거를 해제하세요."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. 탭하여 진동으로 설정하세요. 접근성 서비스가 음소거될 수 있습니다."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. 탭하여 음소거로 설정하세요. 접근성 서비스가 음소거될 수 있습니다."</string>
@@ -584,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>
@@ -760,7 +761,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"브라우저로 이동"</string>
<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-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..4aaae3c 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Көп тондуу жыштык"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Атайын мүмкүнчүлүктөр"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Шыңгыратуу"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Дирилдөө"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Үнсүз"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Үнүн чыгаруу үчүн таптап коюңуз."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Дирилдөөгө коюу үчүн таптап коюңуз. Атайын мүмкүнчүлүктөр кызматынын үнүн өчүрүп койсо болот."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Үнүн өчүрүү үчүн таптап коюңуз. Атайын мүмкүнчүлүктөр кызматынын үнүн өчүрүп койсо болот."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"Серепчиге өтүү"</string>
<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-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..bc1e5b9 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>
@@ -497,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"ບຣູທູດ"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Dual multi tone frequency"</string>
<string name="stream_accessibility" msgid="301136219144385106">"ການຊ່ວຍເຂົ້າເຖິງ"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"ເຕືອນດ້ວຍສຽງ"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"ສັ່ນເຕືອນ"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"ປິດ"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. ແຕະເພື່ອເຊົາປິດສຽງ."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. ແຕະເພື່ອຕັ້ງເປັນສັ່ນ. ບໍລິການຊ່ວຍເຂົ້າເຖິງອາດຖືກປິດສຽງໄວ້."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. ແຕະເພື່ອປິດສຽງ. ບໍລິການຊ່ວຍເຂົ້າເຖິງອາດຖືກປິດສຽງໄວ້."</string>
@@ -585,8 +583,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>
@@ -761,7 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"ໄປທີ່ໂປຣແກຣມທ່ອງເວັບ"</string>
<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-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..53ddcb3 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>
@@ -498,6 +496,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Dvigubas kelių tonų dažnis"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Pritaikymas neįgaliesiems"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Skambinti"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibruoti"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Nutildyti"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Palieskite, kad įjungtumėte garsą."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Palieskite, kad nustatytumėte vibravimą. Gali būti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Palieskite, kad nutildytumėte. Gali būti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
@@ -594,8 +595,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>
@@ -770,7 +771,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Akimirksniu įkeliamos programėlės"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Akimirksniu įkeliamų programėlių nereikia įdiegti."</string>
<string name="app_info" msgid="6856026610594615344">"Programos informacija"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Eiti į žiniatinklį"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Eiti į naršyklę"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobilieji duomenys"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"„Wi-Fi“ išjungtas"</string>
<string name="bt_is_off" msgid="2640685272289706392">"„Bluetooth“ išjungtas"</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..b1c3db5 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Divtoņu daudzfrekvenču signalizācija"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Pieejamība"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Zvanīt"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrēt"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Izslēgt skaņu"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Pieskarieties, lai ieslēgtu skaņu."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Pieskarieties, lai iestatītu uz vibrozvanu. Var tikt izslēgti pieejamības pakalpojumu signāli."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Pieskarieties, lai izslēgtu skaņu. Var tikt izslēgti pieejamības pakalpojumu signāli."</string>
@@ -588,8 +589,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>
@@ -764,7 +765,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Tūlītējās lietotnes"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Tūlītējām lietotnēm nav nepieciešama instalēšana."</string>
<string name="app_info" msgid="6856026610594615344">"Lietotnes informācija"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Pāriet uz tīmekli"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Atvērt pārlūku"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobilie dati"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi ir izslēgts"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth ir izslēgts"</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..3986e16 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Двојна повеќетонска фреквенција"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Пристапност"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Ѕвони"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Вибрации"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Исклучи звук"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Допрете за да вклучите звук."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Допрете за да поставите на вибрации. Можеби ќе се исклучи звукот на услугите за достапност."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Допрете за да исклучите звук. Можеби ќе се исклучи звукот на услугите за достапност."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"Одете на прелистувач"</string>
<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-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 5522e51..3dfde13 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>
@@ -500,6 +492,12 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"ബ്ലൂടൂത്ത്"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"ഡ്യുവൽ മൾട്ടി റ്റോൺ ഫ്രീക്വൻസി"</string>
<string name="stream_accessibility" msgid="301136219144385106">"ഉപയോഗസഹായി"</string>
+ <!-- no translation found for volume_ringer_status_normal (4273142424125855384) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_vibrate (1825615171021346557) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_silent (6896394161022916369) -->
+ <skip />
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. അൺമ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. വൈബ്രേറ്റിലേക്ക് സജ്ജമാക്കുന്നതിന് ടാപ്പുചെയ്യുക. ഉപയോഗസഹായി സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക. ഉപയോഗസഹായി സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
@@ -588,8 +586,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>
@@ -764,7 +762,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"ബ്രൗസറിലേക്ക് പോവുക"</string>
<string name="mobile_data" msgid="7094582042819250762">"മൊബൈൽ ഡാറ്റ"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"വൈഫൈ ഓഫാണ്"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth ഓഫാണ്"</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..9f09dad 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>
@@ -492,6 +490,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Олон дууны давтамж"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Хүртээмж"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Хонх дуугаргах"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Чичиргэх"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Хаах"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Дууг нь нээхийн тулд товшино уу."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Чичиргээнд тохируулахын тулд товшино уу. Хүртээмжийн үйлчилгээний дууг хаасан."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Дууг нь хаахын тулд товшино уу. Хүртээмжийн үйлчилгээний дууг хаасан."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"Хөтчид очих"</string>
<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-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index b882c5e..5b0984d 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"ब्लूटूथ"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"दुहेरी एकाधिक टोन वारंंवारता"</string>
<string name="stream_accessibility" msgid="301136219144385106">"प्रवेशयोग्यता"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"रिंग करा"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"कंपन"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"म्युट करा"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. सशब्द करण्यासाठी टॅप करा."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. कंपन सेट करण्यासाठी टॅप करा. प्रवेशयोग्यता सेवा नि:शब्द केल्या जाऊ शकतात."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. नि:शब्द करण्यासाठी टॅप करा. प्रवेशक्षमता सेवा नि:शब्द केल्या जाऊ शकतात."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"ब्राउझरवर जा"</string>
<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-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..2907761 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Multifrekuensi dwinada"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Kebolehaksesan"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Dering"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Getar"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Redam"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Ketik untuk menyahredam."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Ketik untuk menetapkan pada getar. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Ketik untuk meredam. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Apl Segera"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Apl segera tidak memerlukan pemasangan."</string>
<string name="app_info" msgid="6856026610594615344">"Maklumat apl"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Pergi ke web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Pergi ke penyemak imbas"</string>
<string name="mobile_data" msgid="7094582042819250762">"Data mudah alih"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi dimatikan"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth dimatikan"</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..22375b4 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"ဘလူးတုသ်"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"နှစ်လိုင်းပေါင်း အသံပေါင်းစုံ ကြိမ်နှုန်း"</string>
<string name="stream_accessibility" msgid="301136219144385106">"အများသုံးစွဲနိုင်မှု"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"အသံမြည်သည်"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"တုန်ခါသည်"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"အသံတိတ်သည်"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s။ အသံပြန်ဖွင့်ရန် တို့ပါ။"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s။ တုန်ခါမှုကို သတ်မှတ်ရန် တို့ပါ။ အများသုံးစွဲနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s။ အသံပိတ်ရန် တို့ပါ။ အများသုံးစွဲနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"ချက်ခြင်းသုံးအက်ပ်များကို ထည့်သွင်းစရာမလိုပါ။"</string>
<string name="app_info" msgid="6856026610594615344">"အက်ပ်အချက်အလက်"</string>
- <string name="go_to_web" msgid="1106022723459948514">"ဝဘ်သို့ သွားရန်"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"ဘရောင်ဇာသို့ သွားပါ"</string>
<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-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..51b3b0d 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"DTMF (dual-tone multi-frequency)"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Tilgjengelighet"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Ring"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrer"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Ignorer"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Trykk for å slå på lyden."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Trykk for å angi vibrasjon. Lyden kan bli slått av for tilgjengelighetstjenestene."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Trykk for å slå av lyden. Lyden kan bli slått av for tilgjengelighetstjenestene."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Du trenger ikke å installere instant-apper."</string>
<string name="app_info" msgid="6856026610594615344">"Info om appen"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Gå til nettstedet"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Gå til nettleser"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobildata"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi er av"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth er av"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index e994174..0a63ce2 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>
@@ -500,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"ब्लुटुथ"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"दोहोरो बहु टोनको फ्रिक्वेन्सी"</string>
<string name="stream_accessibility" msgid="301136219144385106">"पहुँच"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"घन्टी"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"कम्पन"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"म्युट गर्नुहोस्"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s। अनम्यूट गर्नका लागि ट्याप गर्नुहोस्।"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s। कम्पनमा सेट गर्नका लागि ट्याप गर्नुहोस्। पहुँच सम्बन्धी सेवाहरू म्यूट हुन सक्छन्।"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s। म्यूट गर्नका लागि ट्याप गर्नुहोस्। पहुँच सम्बन्धी सेवाहरू म्यूट हुन सक्छन्।"</string>
@@ -588,8 +583,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>
@@ -764,7 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"ब्राउजरमा जानुहोस्"</string>
<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-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 640b5d0..ca0fa07 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Frequentie voor tweevoudige multitoon"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Toegankelijkheid"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Bellen"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Trillen"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Dempen"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tik om dempen op te heffen."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tik om in te stellen op trillen. Toegankelijkheidsservices kunnen zijn gedempt."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Tik om te dempen. Toegankelijkheidsservices kunnen zijn gedempt."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant-apps"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Instant-apps hoeven niet te worden geïnstalleerd."</string>
<string name="app_info" msgid="6856026610594615344">"App-info"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Ga naar internet"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Ga naar browser"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobiele data"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wifi is uitgeschakeld"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth is uitgeschakeld"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 48be371..c6475dc 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/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">"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 +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>
@@ -500,6 +492,12 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"ਬਲੂਟੁੱਥ"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"ਦੂਹਰੀ ਮਲਟੀ ਟੋਨ ਆਵਰਤੀ"</string>
<string name="stream_accessibility" msgid="301136219144385106">"ਪਹੁੰਚਯੋਗਤਾ"</string>
+ <!-- no translation found for volume_ringer_status_normal (4273142424125855384) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_vibrate (1825615171021346557) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_silent (6896394161022916369) -->
+ <skip />
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s। ਅਣਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s। ਥਰਥਰਾਹਟ ਸੈੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ। ਪਹੁੰਚਯੋਗਤਾ ਸੇਵਾਵਾਂ ਮਿਊਟ ਹੋ ਸਕਦੀਆਂ ਹਨ।"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s। ਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ। ਪਹੁੰਚਯੋਗਤਾ ਸੇਵਾਵਾਂ ਮਿਊਟ ਹੋ ਸਕਦੀਆਂ ਹਨ।"</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">"Home"</string>
@@ -764,7 +762,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"ਬ੍ਰਾਊਜ਼ਰ \'ਤੇ ਜਾਓ"</string>
<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-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..bc2a954 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>
@@ -498,6 +496,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"DTMF"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Ułatwienia dostępu"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Dzwonek"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Wibracje"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Wyciszenie"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Kliknij, by wyłączyć wyciszenie."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Kliknij, by włączyć wibracje. Ułatwienia dostępu mogą być wyciszone."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Kliknij, by wyciszyć. Ułatwienia dostępu mogą być wyciszone."</string>
@@ -594,8 +595,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>
@@ -770,7 +771,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Aplikacje błyskawiczne"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Aplikacji błyskawicznych nie trzeba instalować."</string>
<string name="app_info" msgid="6856026610594615344">"O aplikacji"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Wejdź na stronę internetową"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Otwórz przeglądarkę"</string>
<string name="mobile_data" msgid="7094582042819250762">"Komórkowa transmisja danych"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi jest wyłączone"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth jest wyłączony"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index ce457be..61aa901 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Multifrequência de dois tons"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Acessibilidade"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Tocar"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrar"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Ignorar"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toque para ativar o som."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toque para configurar para vibrar. É possível que os serviços de acessibilidade sejam silenciados."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
@@ -584,8 +585,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>
@@ -760,7 +761,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Os Instant Apps não requerem instalação."</string>
<string name="app_info" msgid="6856026610594615344">"Informações do app"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Acessar a Web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Abrir o navegador"</string>
<string name="mobile_data" msgid="7094582042819250762">"Dados móveis"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"O Wi-Fi está desativado"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth desativado"</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..7f2c643 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Multifrequência de duas tonalidades"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Acessibilidade"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Toque"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrar"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Desativar som"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toque para reativar o som."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toque para ativar a vibração. Os serviços de acessibilidade podem ser silenciados."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Toque para desativar o som. Os serviços de acessibilidade podem ser silenciados."</string>
@@ -553,13 +554,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 +575,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 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"Ir para o navegador"</string>
<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..61aa901 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Multifrequência de dois tons"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Acessibilidade"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Tocar"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrar"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Ignorar"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toque para ativar o som."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toque para configurar para vibrar. É possível que os serviços de acessibilidade sejam silenciados."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
@@ -584,8 +585,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>
@@ -760,7 +761,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Os Instant Apps não requerem instalação."</string>
<string name="app_info" msgid="6856026610594615344">"Informações do app"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Acessar a Web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Abrir o navegador"</string>
<string name="mobile_data" msgid="7094582042819250762">"Dados móveis"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"O Wi-Fi está desativado"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth desativado"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index c7822e0d..2108455 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>
@@ -498,6 +496,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Frecvență tonuri multiple duale"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Accesibilitate"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Sonerie"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrații"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Blocați"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Atingeți pentru a activa sunetul."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Atingeți pentru a seta vibrarea. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Atingeți pentru a dezactiva sunetul. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
@@ -590,8 +591,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>
@@ -766,7 +767,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Aplicații instantanee"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Aplicațiile instantanee nu necesită instalare."</string>
<string name="app_info" msgid="6856026610594615344">"Informații despre aplicație"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Accesați pe web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Accesați browserul"</string>
<string name="mobile_data" msgid="7094582042819250762">"Date mobile"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Conexiunea Wi-Fi este dezactivată"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Funcția Bluetooth este dezactivată"</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..ac4f5fe 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>
@@ -500,6 +498,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Тональный набор"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Специальные возможности"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Со звуком"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Вибрация"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Без звука"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Нажмите, чтобы включить звук."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Нажмите, чтобы включить вибрацию. Специальные возможности могут прекратить работу."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Нажмите, чтобы выключить звук. Специальные возможности могут прекратить работу."</string>
@@ -555,7 +556,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 +597,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>
@@ -772,7 +773,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"Перейти в браузер"</string>
<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-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..12f4838 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"බ්ලූටූත්"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"ද්විත්ව බහු ස්වර සංඛ්යාතය"</string>
<string name="stream_accessibility" msgid="301136219144385106">"ප්රවේශ්යතාව"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"නාද කරන්න"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"කම්පනය කරන්න"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"නිහඬ කරන්න"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. නිහඬ කිරීම ඉවත් කිරීමට තට්ටු කරන්න."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. කම්පනය කිරීමට තට්ටු කරන්න. ප්රවේශ්යතා සේවා නිහඬ කළ හැකිය."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. නිහඬ කිරීමට තට්ටු කරන්න. ප්රවේශ්යතා සේවා නිහඬ කළ හැකිය."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"බ්රවුසරය වෙත යන්න"</string>
<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-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..151c2b4 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>
@@ -500,6 +498,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Dvojtónová multifrekvencia"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Dostupnosť"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Prezvoniť"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrovať"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Vypnúť zvuk"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Klepnutím zapnite zvuk."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Klepnutím aktivujte režim vibrovania. Služby dostupnosti je možné stlmiť."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Klepnutím vypnite zvuk. Služby dostupnosti je možné stlmiť."</string>
@@ -596,8 +597,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>
@@ -772,7 +773,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Okamžité aplikácie"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Okamžité aplikácie nevyžadujú inštaláciu."</string>
<string name="app_info" msgid="6856026610594615344">"Info o aplikácii"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Prejsť na internet"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Otvoriť prehliadač"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobilné dáta"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Pripojenie Wi‑Fi je vypnuté"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Rozhranie Bluetooth je vypnuté"</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..ee628e1 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>
@@ -500,6 +498,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Dvojna večtonska frekvenca"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Funkcije za ljudi s posebnimi potrebami"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Zvonjenje"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibriranje"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Utišano"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Dotaknite se, če želite vklopiti zvok."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Dotaknite se, če želite nastaviti vibriranje. V storitvah za ljudi s posebnimi potrebami bo morda izklopljen zvok."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Dotaknite se, če želite izklopiti zvok. V storitvah za ljudi s posebnimi potrebami bo morda izklopljen zvok."</string>
@@ -596,8 +597,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>
@@ -772,7 +773,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Nenamestljive aplikacije"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Nenamestljivih aplikacij ni treba namestiti."</string>
<string name="app_info" msgid="6856026610594615344">"Podatki o aplikaciji"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Pojdi v splet"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Odpri brskalnik"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobilni podatki"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi je izklopljen"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth je izklopljen"</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..7641e6c 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Frekuenca e dyfishtë me shumë tone"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Qasshmëria"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Bjeri ziles"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Dridhje"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Pa zë"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Trokit për të aktivizuar."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Trokit për ta caktuar te dridhja. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Trokit për të çaktivizuar. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Aplikacionet e çastit"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Aplikacionet e çastit nuk kërkojnë instalim."</string>
<string name="app_info" msgid="6856026610594615344">"Informacioni mbi aplikacionin"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Shko në ueb"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Shko te shfletuesi"</string>
<string name="mobile_data" msgid="7094582042819250762">"Të dhënat celulare"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi është joaktiv"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth-i është joaktiv"</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..b5fab0d 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Вишеструка фреквенција дуалног тона"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Приступачност"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Активирај звоно"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Вибрирај"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Искључи звук"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Додирните да бисте укључили звук."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Додирните да бисте подесили на вибрацију. Звук услуга приступачности ће можда бити искључен."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Додирните да бисте искључили звук. Звук услуга приступачности ће можда бити искључен."</string>
@@ -588,8 +589,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>
@@ -764,7 +765,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"Иди на прегледач"</string>
<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-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..cc6f542 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Tonval"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Tillgänglighet"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Ringsignal"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibration"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Dölj"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tryck här om du vill slå på ljudet."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tryck här om du vill sätta på vibrationen. Tillgänglighetstjänster kanske inaktiveras."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Tryck här om du vill stänga av ljudet. Tillgänglighetstjänsterna kanske inaktiveras."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Snabbappar behöver inte installeras."</string>
<string name="app_info" msgid="6856026610594615344">"Info om appen"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Öppna webbplatsen"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Öppna webbläsaren"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobildata"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi är inaktiverat"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth är inaktiverat"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 5853d93..b83f10f 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Masafa ya ishara ya kampuni ya simu"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Zana za walio na matatizo ya kuona au kusikia"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Piga"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Tetema"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Zima sauti"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Gusa ili urejeshe."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Gusa ili uweke mtetemo. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Gusa ili ukomeshe. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Programu Zinazofunguka Papo Hapo"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Huhitaji kusakinisha programu zinazofunguka papo hapo."</string>
<string name="app_info" msgid="6856026610594615344">"Maelezo ya programu"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Nenda kwenye wavuti"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Tumia kivinjari"</string>
<string name="mobile_data" msgid="7094582042819250762">"Data ya mtandao wa simu"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi imezimwa"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth imezimwa"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 9972c73..9d532e2 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/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>
@@ -494,6 +492,12 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"புளூடூத்"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"டூயல் டோன் மல்டி ஃப்ரீக்வென்சி"</string>
<string name="stream_accessibility" msgid="301136219144385106">"அணுகல்தன்மை"</string>
+ <!-- no translation found for volume_ringer_status_normal (4273142424125855384) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_vibrate (1825615171021346557) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_silent (6896394161022916369) -->
+ <skip />
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. ஒலி இயக்க, தட்டவும்."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. அதிர்விற்கு அமைக்க, தட்டவும். அணுகல்தன்மை சேவைகள் ஒலியடக்கப்படக்கூடும்."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. ஒலியடக்க, தட்டவும். அணுகல்தன்மை சேவைகள் ஒலியடக்கப்படக்கூடும்."</string>
@@ -582,8 +586,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>
@@ -758,7 +762,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"உலாவிக்குக்குச் செல்"</string>
<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-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 0652de9..f1c66f5 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/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="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">"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>
@@ -500,6 +492,12 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"బ్లూటూత్"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"డ్యూయల్ మల్టీ టోన్ ఫ్రీక్వెన్సీ"</string>
<string name="stream_accessibility" msgid="301136219144385106">"యాక్సెస్ సామర్థ్యం"</string>
+ <!-- no translation found for volume_ringer_status_normal (4273142424125855384) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_vibrate (1825615171021346557) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_silent (6896394161022916369) -->
+ <skip />
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. అన్మ్యూట్ చేయడానికి నొక్కండి."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. వైబ్రేషన్కు సెట్ చేయడానికి నొక్కండి. యాక్సెస్ సామర్థ్య సేవలు మ్యూట్ చేయబడవచ్చు."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. మ్యూట్ చేయడానికి నొక్కండి. యాక్సెస్ సామర్థ్య సేవలు మ్యూట్ చేయబడవచ్చు."</string>
@@ -588,8 +586,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>
@@ -764,7 +762,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"బ్రౌజర్కు వెళ్లండి"</string>
<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-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..ea61018 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"บลูทูธ"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"การส่งสัญญาณเสียงแบบ 2 เสียงพร้อมกัน"</string>
<string name="stream_accessibility" msgid="301136219144385106">"การเข้าถึง"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"ทำให้ส่งเสียง"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"สั่น"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"ปิดเสียง"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s แตะเพื่อเปิดเสียง"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s แตะเพื่อตั้งค่าให้สั่น อาจมีการปิดเสียงบริการการเข้าถึง"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s แตะเพื่อปิดเสียง อาจมีการปิดเสียงบริการการเข้าถึง"</string>
@@ -582,8 +583,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 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant App"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Instant Apps ไม่ต้องใช้การติดตั้ง"</string>
<string name="app_info" msgid="6856026610594615344">"ข้อมูลแอป"</string>
- <string name="go_to_web" msgid="1106022723459948514">"ไปที่เว็บ"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"ไปที่เบราว์เซอร์"</string>
<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-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..cdf28d6 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Dual multi tone frequency"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Pagiging Naa-access"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Ipa-ring"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"I-vibrate"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"I-mute"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. I-tap upang i-unmute."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. I-tap upang itakda na mag-vibrate. Maaaring i-mute ang mga serbisyo sa Accessibility."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. I-tap upang i-mute. Maaaring i-mute ang mga serbisyo sa Accessibility."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Hindi kailangang i-install ang mga instant na app."</string>
<string name="app_info" msgid="6856026610594615344">"Impormasyon ng app"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Pumunta sa web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Pumunta sa browser"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Naka-off ang Wi-Fi"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Naka-off ang Bluetooth"</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..5dc81a1 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Çift ton çoklu frekans"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Erişilebilirlik"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Zili çaldır"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Titreşim"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Sesi kapat"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Sesi açmak için dokunun."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Titreşime ayarlamak için dokunun. Erişilebilirlik hizmetlerinin sesi kapatılabilir."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Sesi kapatmak için dokunun. Erişilebilirlik hizmetlerinin sesi kapatılabilir."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Hazır Uygulamalar"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Hazır uygulamaların yüklenmesi gerekmez."</string>
<string name="app_info" msgid="6856026610594615344">"Uygulama bilgileri"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Web\'e git"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Tarayıcıya git"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobil veriler"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Kablosuz bağlantı kapalı"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth kapalı"</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..8fa1b72 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>
@@ -500,6 +498,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Двотональний багаточастотний аналоговий сигнал"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Спеціальні можливості"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Дзвінок"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Вібросигнал"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Без звуку"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Торкніться, щоб увімкнути звук."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Торкніться, щоб налаштувати вібросигнал. Спеціальні можливості може бути вимкнено."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Торкніться, щоб вимкнути звук. Спеціальні можливості може бути вимкнено."</string>
@@ -596,8 +597,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 +773,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"Веб-переглядач"</string>
<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..6498088 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/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>
@@ -500,6 +492,12 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"بلوٹوتھ"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"دوہری ملٹی ٹون فریکوئنسی"</string>
<string name="stream_accessibility" msgid="301136219144385106">"ایکسیسبیلٹی"</string>
+ <!-- no translation found for volume_ringer_status_normal (4273142424125855384) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_vibrate (1825615171021346557) -->
+ <skip />
+ <!-- no translation found for volume_ringer_status_silent (6896394161022916369) -->
+ <skip />
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s۔ آواز چالو کرنے کیلئے تھپتھپائیں۔"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s۔ ارتعاش پر سیٹ کرنے کیلئے تھپتھپائیں۔ ایکسیسبیلٹی سروسز شاید خاموش ہوں۔"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔ ایکسیسبیلٹی سروسز شاید خاموش ہوں۔"</string>
@@ -588,8 +586,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>
@@ -764,7 +762,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"براؤزر پر جائیں"</string>
<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-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..273079d 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Ikkitali ko‘pchastotali ovoz"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Maxsus imkoniyatlar"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Jiringlatish"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Tebranish"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Ovozsiz"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Ovozini yoqish uchun ustiga bosing."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tebranishni yoqish uchun ustiga bosing. Maxsus imkoniyatlar ishlamasligi mumkin."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Ovozini o‘chirish uchun ustiga bosing. Maxsus imkoniyatlar ishlamasligi mumkin."</string>
@@ -584,8 +585,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>
@@ -760,7 +761,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Darhol ochiladigan ilovalar"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Darhol ochiladigan ilovalarni o‘rnatish shart emas."</string>
<string name="app_info" msgid="6856026610594615344">"Ilova haqida"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Brauzerga o‘tish"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Brauzerni ochish"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobil internet"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi o‘chiq"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth o‘chiq"</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..df06298 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Tần số đa chuông kép"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Trợ năng"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Đổ chuông"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Rung"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Tắt tiếng"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Nhấn để bật tiếng."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Nhấn để đặt chế độ rung. Bạn có thể tắt tiếng dịch vụ trợ năng."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Nhấn để tắt tiếng. Bạn có thể tắt tiếng dịch vụ trợ năng."</string>
@@ -584,8 +585,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>
@@ -760,7 +761,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Ứng dụng tức thì"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Ứng dụng tức thì không yêu cầu cài đặt."</string>
<string name="app_info" msgid="6856026610594615344">"Thông tin ứng dụng"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Truy cập web"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Đi tới trình duyệt"</string>
<string name="mobile_data" msgid="7094582042819250762">"Dữ liệu di động"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi tắt"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth tắt"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 74afc22..f7999a6 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>
@@ -500,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"蓝牙"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"双音多频"</string>
<string name="stream_accessibility" msgid="301136219144385106">"无障碍"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"响铃"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"振动"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"静音"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s。点按即可取消静音。"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s。点按即可设为振动,但可能会同时将无障碍服务设为静音。"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s。点按即可设为静音,但可能会同时将无障碍服务设为静音。"</string>
@@ -588,8 +583,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>
@@ -764,7 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"转到浏览器"</string>
<string name="mobile_data" msgid="7094582042819250762">"移动数据"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"WLAN 已关闭"</string>
<string name="bt_is_off" msgid="2640685272289706392">"蓝牙已关闭"</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..188ad7c 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>
@@ -496,6 +494,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"藍牙"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"雙音多頻訊號"</string>
<string name="stream_accessibility" msgid="301136219144385106">"無障礙功能"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"鈴聲"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"震動"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"靜音"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s。輕按即可取消靜音。"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s。輕按即可設為震動。無障礙功能服務可能已經設為靜音。"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s。輕按即可設為靜音。無障礙功能服務可能已經設為靜音。"</string>
@@ -584,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>
@@ -760,7 +761,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"前往瀏覽器"</string>
<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-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..75f8015 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"藍牙"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"雙音多頻"</string>
<string name="stream_accessibility" msgid="301136219144385106">"協助工具"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"鈴聲"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"震動"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"靜音"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s。輕觸即可取消靜音。"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s。輕觸即可設為震動,但系統可能會將無障礙服務一併設為靜音。"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s。輕觸即可設為靜音,但系統可能會將無障礙服務一併設為靜音。"</string>
@@ -582,8 +583,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 +759,7 @@
<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>
+ <string name="go_to_web" msgid="2650669128861626071">"前往瀏覽器"</string>
<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-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..b3b26dc 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>
@@ -494,6 +492,9 @@
<string name="stream_bluetooth_sco" msgid="2055645746402746292">"I-Bluetooth"</string>
<string name="stream_dtmf" msgid="2447177903892477915">"Ifrikhwensi yethoni engakuningi"</string>
<string name="stream_accessibility" msgid="301136219144385106">"Ukufinyeleleka"</string>
+ <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Khalisa"</string>
+ <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Dlidlizela"</string>
+ <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Thulisa"</string>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Thepha ukuze ususe ukuthula."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Thepha ukuze usethe ukudlidliza. Amasevisi okufinyelela angathuliswa."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Thepha ukuze uthulise. Amasevisi okufinyelela angathuliswa."</string>
@@ -582,8 +583,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>
@@ -758,7 +759,7 @@
<string name="instant_apps" msgid="6647570248119804907">"Izinhlelo zokusebenza ezisheshayo"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Izinhlelo zokusebenza ezisheshayo azidingi ukufakwa."</string>
<string name="app_info" msgid="6856026610594615344">"Ulwazi lohlelo lokusebenza"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Iya kuwebhu"</string>
+ <string name="go_to_web" msgid="2650669128861626071">"Iya kusiphequluli"</string>
<string name="mobile_data" msgid="7094582042819250762">"Idatha yeselula"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"I-Wi-Fi ivaliwe"</string>
<string name="bt_is_off" msgid="2640685272289706392">"I-Bluetooth ivaliwe"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 8e065d1..e313e86 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -301,6 +301,9 @@
<!-- Enable the default volume dialog -->
<bool name="enable_volume_ui">true</bool>
+ <!-- Enable the default volume level warning dialog -->
+ <bool name="enable_safety_warning">true</bool>
+
<!-- Whether to show operator name in the status bar -->
<bool name="config_showOperatorNameInStatusBar">false</bool>
@@ -316,6 +319,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/strings.xml b/packages/SystemUI/res/values/strings.xml
index ca85445..78e621e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1248,6 +1248,11 @@
<string name="stream_tts" translatable="false">Transmitted Through Speaker</string> <!-- STREAM_TTS -->
<string name="stream_accessibility">Accessibility</string> <!-- STREAM_ACCESSIBILITY -->
+ <string name="ring_toggle_title">Calls</string>
+ <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 +1994,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/shared/tests/Android.mk b/packages/SystemUI/shared/tests/Android.mk
index ce3b442..239a4e3 100644
--- a/packages/SystemUI/shared/tests/Android.mk
+++ b/packages/SystemUI/shared/tests/Android.mk
@@ -38,7 +38,6 @@
mockito-target-minus-junit4 \
SystemUI-proto \
SystemUI-tags \
- legacy-android-test \
testables \
truth-prebuilt \
@@ -50,4 +49,4 @@
ifeq ($(EXCLUDE_SYSTEMUI_TESTS),)
include $(BUILD_PACKAGE)
-endif
\ No newline at end of file
+endif
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/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 41b007a..d58b69d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -347,6 +347,7 @@
private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray();
private static int sCurrentUser;
+ private Runnable mUpdateFingerprintListeningState = this::updateFingerprintListeningState;
public synchronized static void setCurrentUser(int currentUser) {
sCurrentUser = currentUser;
@@ -1666,7 +1667,8 @@
public void setSwitchingUser(boolean switching) {
mSwitchingUser = switching;
- updateFingerprintListeningState();
+ // Since this comes in on a binder thread, we need to post if first
+ mHandler.post(mUpdateFingerprintListeningState);
}
private void sendUpdates(KeyguardUpdateMonitorCallback callback) {
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 526a8f4..ebeb351 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -26,7 +26,11 @@
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.Dependency.DependencyProvider;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.NotificationGutsManager;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
@@ -34,12 +38,10 @@
import com.android.systemui.statusbar.phone.LockIcon;
import com.android.systemui.statusbar.phone.LockscreenWallpaper;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBar;
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;
@@ -108,10 +110,14 @@
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));
+ providers.put(NotificationRemoteInputManager.class,
+ () -> new NotificationRemoteInputManager(
+ 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/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 6f8bcff..a409fcb 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -63,7 +63,7 @@
new DozeFalsingManagerAdapter(FalsingManager.getInstance(context)),
createDozeTriggers(context, sensorManager, host, alarmManager, config, params,
handler, wakeLock, machine),
- createDozeUi(context, host, wakeLock, machine, handler, alarmManager),
+ createDozeUi(context, host, wakeLock, machine, handler, alarmManager, params),
new DozeScreenState(wrappedService, handler),
createDozeScreenBrightness(context, wrappedService, sensorManager, host, handler),
});
@@ -89,8 +89,9 @@
}
private DozeMachine.Part createDozeUi(Context context, DozeHost host, WakeLock wakeLock,
- DozeMachine machine, Handler handler, AlarmManager alarmManager) {
- return new DozeUi(context, alarmManager, machine, wakeLock, host, handler);
+ DozeMachine machine, Handler handler, AlarmManager alarmManager,
+ DozeParameters params) {
+ return new DozeUi(context, alarmManager, machine, wakeLock, host, handler, params);
}
public static DozeHost getHost(DozeService service) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 2f607ee..6a29299 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -38,6 +38,7 @@
void extendPulse();
void setAnimateWakeup(boolean animateWakeup);
+ void setAnimateScreenOff(boolean animateScreenOff);
void onDoubleTap(float x, float y);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 851b78c..b352ec9 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -23,6 +23,7 @@
import android.text.format.Formatter;
import android.util.Log;
+import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.AlarmTimeout;
import com.android.systemui.util.wakelock.WakeLock;
@@ -41,18 +42,22 @@
private final WakeLock mWakeLock;
private final DozeMachine mMachine;
private final AlarmTimeout mTimeTicker;
+ private final boolean mCanAnimateWakeup;
private long mLastTimeTickElapsed = 0;
public DozeUi(Context context, AlarmManager alarmManager, DozeMachine machine,
- WakeLock wakeLock, DozeHost host, Handler handler) {
+ WakeLock wakeLock, DozeHost host, Handler handler,
+ DozeParameters params) {
mContext = context;
mMachine = machine;
mWakeLock = wakeLock;
mHost = host;
mHandler = handler;
+ mCanAnimateWakeup = !params.getDisplayNeedsBlanking();
mTimeTicker = new AlarmTimeout(alarmManager, this::onTimeTick, "doze_time_tick", handler);
+ mHost.setAnimateScreenOff(params.getCanControlScreenOffAnimation());
}
private void pulseWhileDozing(int reason) {
@@ -106,7 +111,7 @@
// Keep current state.
break;
default:
- mHost.setAnimateWakeup(false);
+ mHost.setAnimateWakeup(mCanAnimateWakeup);
break;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 00e8b1a..5c8c3f3 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.isLogoutEnabled()
+ && 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 c92acd0..8fa66e0f 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;
@@ -169,7 +164,6 @@
private static final int NOTIFY_SCREEN_TURNED_ON = 15;
private static final int NOTIFY_SCREEN_TURNED_OFF = 16;
private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 17;
- private static final int SET_SWITCHING_USER = 18;
/**
* The default amount of time we stay awake (used for all key input)
@@ -1424,11 +1418,7 @@
}
public void setSwitchingUser(boolean switching) {
- Trace.beginSection("KeyguardViewMediator#setSwitchingUser");
- mHandler.removeMessages(SET_SWITCHING_USER);
- Message msg = mHandler.obtainMessage(SET_SWITCHING_USER, switching ? 1 : 0, 0);
- mHandler.sendMessage(msg);
- Trace.endSection();
+ KeyguardUpdateMonitor.getInstance(mContext).setSwitchingUser(switching);
}
/**
@@ -1568,11 +1558,6 @@
Log.w(TAG, "Timeout while waiting for activity drawn!");
Trace.endSection();
break;
- case SET_SWITCHING_USER:
- Trace.beginSection("KeyguardViewMediator#handleMessage SET_SWITCHING_USER");
- KeyguardUpdateMonitor.getInstance(mContext).setSwitchingUser(msg.arg1 != 0);
- Trace.endSection();
- break;
}
}
};
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 9400fd8..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;
@@ -657,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/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 e909644..6db46b5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -38,7 +38,6 @@
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
@@ -49,7 +48,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;
@@ -59,10 +57,13 @@
import android.util.DisplayMetrics;
import android.util.Slog;
import android.view.Display;
+import android.view.DisplayListCanvas;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.RenderNode;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -154,7 +155,6 @@
int previewWidth = data.previewWidth;
int previewHeight = data.previewheight;
- Canvas c = new Canvas();
Paint paint = new Paint();
ColorMatrix desat = new ColorMatrix();
desat.setSaturation(0.25f);
@@ -162,23 +162,17 @@
Matrix matrix = new Matrix();
int overlayColor = 0x40FFFFFF;
- 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);
- c.drawColor(overlayColor);
- c.setBitmap(null);
+ Bitmap picture = generateAdjustedHwBitmap(data.image, previewWidth, previewHeight, matrix,
+ paint, overlayColor);
// 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, Bitmap.Config.ARGB_8888);
matrix.setScale(scale, scale);
matrix.postTranslate((iconSize - (scale * mImageWidth)) / 2,
(iconSize - (scale * mImageHeight)) / 2);
- c.setBitmap(icon);
- c.drawBitmap(data.image, matrix, paint);
- c.drawColor(overlayColor);
- c.setBitmap(null);
+ Bitmap icon = generateAdjustedHwBitmap(data.image, iconSize, iconSize, matrix, paint,
+ overlayColor);
// Show the intermediate notification
mTickerAddSpace = !mTickerAddSpace;
@@ -232,6 +226,22 @@
mNotificationStyle.bigLargeIcon((Bitmap) null);
}
+ /**
+ * Generates a new hardware bitmap with specified values, copying the content from the passed
+ * in bitmap.
+ */
+ private Bitmap generateAdjustedHwBitmap(Bitmap bitmap, int width, int height, Matrix matrix,
+ Paint paint, int color) {
+ RenderNode node = RenderNode.create("ScreenshotCanvas", null);
+ node.setLeftTopRightBottom(0, 0, width, height);
+ node.setClipToBounds(false);
+ DisplayListCanvas canvas = node.start(width, height);
+ canvas.drawColor(color);
+ canvas.drawBitmap(bitmap, matrix, paint);
+ node.end(canvas);
+ return ThreadedRenderer.createHardwareBitmap(node, width, height);
+ }
+
@Override
protected Void doInBackground(Void... params) {
if (isCancelled()) {
@@ -557,25 +567,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 +582,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 +593,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 +624,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/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 23d9cae..f53eb48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -112,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;
@@ -205,7 +206,7 @@
private OnClickListener mExpandClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
- if (!mShowingPublic && (!mIsLowPriority || isExpanded())
+ if (!shouldShowPublic() && (!mIsLowPriority || isExpanded())
&& mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
mGroupExpansionChanging = true;
final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
@@ -491,6 +492,7 @@
notifyHeightChanged(false /* needsAnimation */);
}
if (isHeadsUp) {
+ mMustStayOnScreen = true;
setAboveShelf(true);
} else if (isAboveShelf() != wasAboveShelf) {
mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
@@ -517,6 +519,12 @@
addChildNotification(row, -1);
}
+ @Override
+ public void setHeadsUpIsVisible() {
+ super.setHeadsUpIsVisible();
+ mMustStayOnScreen = false;
+ }
+
/**
* Add a child notification to this view.
*
@@ -782,7 +790,7 @@
* {@link #getNotificationHeader()} in case it is a low-priority group.
*/
public NotificationHeaderView getVisibleNotificationHeader() {
- if (mIsSummaryWithChildren && !mShowingPublic) {
+ if (mIsSummaryWithChildren && !shouldShowPublic()) {
return mChildrenContainer.getVisibleHeader();
}
return getShowingLayout().getVisibleNotificationHeader();
@@ -1504,10 +1512,10 @@
}
private void updateChildrenVisibility() {
- mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
+ mPrivateLayout.setVisibility(!shouldShowPublic() && !mIsSummaryWithChildren ? VISIBLE
: INVISIBLE);
if (mChildrenContainer != null) {
- mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
+ mChildrenContainer.setVisibility(!shouldShowPublic() && mIsSummaryWithChildren ? VISIBLE
: INVISIBLE);
}
// The limits might have changed if the view suddenly became a group or vice versa
@@ -1558,7 +1566,7 @@
}
public boolean isExpandable() {
- if (mIsSummaryWithChildren && !mShowingPublic) {
+ if (mIsSummaryWithChildren && !shouldShowPublic()) {
return !mChildrenExpanded;
}
return mEnableNonGroupedNotificationExpand && mExpandable;
@@ -1603,7 +1611,7 @@
*/
public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
mFalsingManager.setNotificationExpanded();
- if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion
+ if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
&& !mChildrenContainer.showingAsLowPriority()) {
final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
@@ -1898,7 +1906,7 @@
mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
updateChildrenVisibility();
} else {
- animateShowingPublic(delay, duration);
+ animateShowingPublic(delay, duration, mShowingPublic);
}
NotificationContentView showingLayout = getShowingLayout();
showingLayout.updateBackgroundColor(animated);
@@ -1908,13 +1916,13 @@
mShowingPublicInitialized = true;
}
- private void animateShowingPublic(long delay, long duration) {
+ private void animateShowingPublic(long delay, long duration, boolean showingPublic) {
View[] privateViews = mIsSummaryWithChildren
? new View[] {mChildrenContainer}
: new View[] {mPrivateLayout};
View[] publicViews = new View[] {mPublicLayout};
- View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
- View[] shownChildren = mShowingPublic ? publicViews : privateViews;
+ View[] hiddenChildren = showingPublic ? privateViews : publicViews;
+ View[] shownChildren = showingPublic ? publicViews : privateViews;
for (final View hiddenView : hiddenChildren) {
hiddenView.setVisibility(View.VISIBLE);
hiddenView.animate().cancel();
@@ -1942,7 +1950,7 @@
@Override
public boolean mustStayOnScreen() {
- return mIsHeadsUp;
+ return mIsHeadsUp && mMustStayOnScreen;
}
/**
@@ -1951,7 +1959,11 @@
* see {@link #isClearable()}.
*/
public boolean canViewBeDismissed() {
- return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
+ return isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
+ }
+
+ private boolean shouldShowPublic() {
+ return mSensitive && mHideSensitiveForIntrinsicHeight;
}
public void makeActionsVisibile() {
@@ -1997,7 +2009,7 @@
@Override
public boolean isContentExpandable() {
- if (mIsSummaryWithChildren && !mShowingPublic) {
+ if (mIsSummaryWithChildren && !shouldShowPublic()) {
return true;
}
NotificationContentView showingLayout = getShowingLayout();
@@ -2006,7 +2018,7 @@
@Override
protected View getContentView() {
- if (mIsSummaryWithChildren && !mShowingPublic) {
+ if (mIsSummaryWithChildren && !shouldShowPublic()) {
return mChildrenContainer;
}
return getShowingLayout();
@@ -2071,7 +2083,7 @@
@Override
public int getMaxContentHeight() {
- if (mIsSummaryWithChildren && !mShowingPublic) {
+ if (mIsSummaryWithChildren && !shouldShowPublic()) {
return mChildrenContainer.getMaxContentHeight();
}
NotificationContentView showingLayout = getShowingLayout();
@@ -2085,7 +2097,7 @@
} else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp
&& mHeadsUpManager.isTrackingHeadsUp()) {
return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
- } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
+ } else if (mIsSummaryWithChildren && !isGroupExpanded() && !shouldShowPublic()) {
return mChildrenContainer.getMinHeight();
} else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp) {
return mHeadsUpHeight;
@@ -2096,7 +2108,7 @@
@Override
public int getCollapsedHeight() {
- if (mIsSummaryWithChildren && !mShowingPublic) {
+ if (mIsSummaryWithChildren && !shouldShowPublic()) {
return mChildrenContainer.getCollapsedHeight();
}
return getMinHeight();
@@ -2136,7 +2148,7 @@
}
public NotificationContentView getShowingLayout() {
- return mShowingPublic ? mPublicLayout : mPrivateLayout;
+ return shouldShowPublic() ? mPublicLayout : mPrivateLayout;
}
public void setLegacy(boolean legacy) {
@@ -2242,7 +2254,7 @@
if (header != null && header.isInTouchRect(x - getTranslation(), y)) {
return true;
}
- if ((!mIsSummaryWithChildren || mShowingPublic)
+ if ((!mIsSummaryWithChildren || shouldShowPublic())
&& getShowingLayout().disallowSingleClick(x, y)) {
return true;
}
@@ -2272,7 +2284,7 @@
if (canViewBeDismissed()) {
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
}
- boolean expandable = mShowingPublic;
+ boolean expandable = shouldShowPublic();
boolean isExpanded = false;
if (!expandable) {
if (mIsSummaryWithChildren) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index b3d6e32..db19d2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -80,10 +80,21 @@
private final ViewOutlineProvider mProvider = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
- 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);
+ 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 {
+ 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);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 18b9860..f762513 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -478,6 +478,9 @@
return false;
}
+ public void setHeadsUpIsVisible() {
+ }
+
public boolean isChildInGroup() {
return false;
}
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..4952da4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.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.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 NotificationRemoteInputManager mRemoteInputManager;
+ private final Context mContext;
+
+ public NotificationListener(NotificationPresenter presenter,
+ NotificationRemoteInputManager remoteInputManager, Context context) {
+ mPresenter = presenter;
+ mRemoteInputManager = remoteInputManager;
+ 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();
+ mRemoteInputManager.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/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index 1aca60c..33c7253 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -16,7 +16,11 @@
package com.android.systemui.statusbar;
import android.content.Intent;
+import android.os.Handler;
import android.service.notification.NotificationListenerService;
+import android.view.View;
+
+import java.util.Set;
/**
* An abstraction of something that presents notifications, e.g. StatusBar. Contains methods
@@ -25,7 +29,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, NotificationRemoteInputManager.Callback {
/**
* Returns true if the presenter is not visible. For example, it may not be necessary to do
@@ -39,11 +44,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 +54,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 +70,41 @@
*/
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();
+
+ /**
+ * Called when the current user changes.
+ * @param newUserId new user id
+ */
+ void onUserSwitched(int newUserId);
+
+ /**
+ * Gets the NotificationLockscreenUserManager for this Presenter.
+ */
+ NotificationLockscreenUserManager getNotificationLockscreenUserManager();
+
+ /**
+ * Wakes the device up if dozing.
+ *
+ * @param time the time when the request to wake up was issued
+ * @param where which view caused this wake up request
+ */
+ void wakeUpIfDozing(long time, View where);
+
+ /**
+ * True if the device currently requires a PIN, pattern, or password to unlock.
+ *
+ * @param userId user id to query about
+ * @return true iff the device is locked
+ */
+ boolean isDeviceLocked(int userId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
new file mode 100644
index 0000000..7827f62
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -0,0 +1,441 @@
+/*
+ * 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.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
+
+import android.app.ActivityManager;
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserManager;
+import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.policy.RemoteInputView;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Set;
+
+/**
+ * Class for handling remote input state over a set of notifications. This class handles things
+ * like keeping notifications temporarily that were cancelled as a response to a remote input
+ * interaction, keeping track of notifications to remove when NotificationPresenter is collapsed,
+ * and handling clicks on remote views.
+ */
+public class NotificationRemoteInputManager implements Dumpable {
+ public static final boolean ENABLE_REMOTE_INPUT =
+ SystemProperties.getBoolean("debug.enable_remote_input", true);
+ public static final boolean FORCE_REMOTE_INPUT_HISTORY =
+ SystemProperties.getBoolean("debug.force_remoteinput_history", true);
+ private static final boolean DEBUG = false;
+ private static final String TAG = "NotificationRemoteInputManager";
+
+ /**
+ * How long to wait before auto-dismissing a notification that was kept for remote input, and
+ * has now sent a remote input. We auto-dismiss, because the app may not see a reason to cancel
+ * these given that they technically don't exist anymore. We wait a bit in case the app issues
+ * an update.
+ */
+ private static final int REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY = 200;
+
+ protected final ArraySet<NotificationData.Entry> mRemoteInputEntriesToRemoveOnCollapse =
+ new ArraySet<>();
+ protected final NotificationLockscreenUserManager mLockscreenUserManager;
+
+ /**
+ * Notifications with keys in this set are not actually around anymore. We kept them 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.
+ */
+ protected final ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
+ protected final Context mContext;
+ private final UserManager mUserManager;
+
+ protected RemoteInputController mRemoteInputController;
+ protected NotificationPresenter mPresenter;
+ protected IStatusBarService mBarService;
+ protected Callback mCallback;
+
+ private final RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
+
+ @Override
+ public boolean onClickHandler(
+ final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
+ mPresenter.wakeUpIfDozing(SystemClock.uptimeMillis(), view);
+
+ if (handleRemoteInput(view, pendingIntent)) {
+ return true;
+ }
+
+ if (DEBUG) {
+ Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
+ }
+ logActionClick(view);
+ // The intent we are sending is for the application, which
+ // won't have permission to immediately start an activity after
+ // the user switches to home. We know it is safe to do at this
+ // point, so make sure new activity switches are now allowed.
+ try {
+ ActivityManager.getService().resumeAppSwitches();
+ } catch (RemoteException e) {
+ }
+ return mCallback.handleRemoteViewClick(view, pendingIntent, fillInIntent,
+ () -> superOnClickHandler(view, pendingIntent, fillInIntent));
+ }
+
+ private void logActionClick(View view) {
+ ViewParent parent = view.getParent();
+ String key = getNotificationKeyForParent(parent);
+ if (key == null) {
+ Log.w(TAG, "Couldn't determine notification for click.");
+ return;
+ }
+ int index = -1;
+ // If this is a default template, determine the index of the button.
+ if (view.getId() == com.android.internal.R.id.action0 &&
+ parent != null && parent instanceof ViewGroup) {
+ ViewGroup actionGroup = (ViewGroup) parent;
+ index = actionGroup.indexOfChild(view);
+ }
+ try {
+ mBarService.onNotificationActionClick(key, index);
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ }
+
+ private String getNotificationKeyForParent(ViewParent parent) {
+ while (parent != null) {
+ if (parent instanceof ExpandableNotificationRow) {
+ return ((ExpandableNotificationRow) parent)
+ .getStatusBarNotification().getKey();
+ }
+ parent = parent.getParent();
+ }
+ return null;
+ }
+
+ private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
+ Intent fillInIntent) {
+ return super.onClickHandler(view, pendingIntent, fillInIntent,
+ WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
+ }
+
+ private boolean handleRemoteInput(View view, PendingIntent pendingIntent) {
+ if (mCallback.shouldHandleRemoteInput(view, pendingIntent)) {
+ return true;
+ }
+
+ Object tag = view.getTag(com.android.internal.R.id.remote_input_tag);
+ RemoteInput[] inputs = null;
+ if (tag instanceof RemoteInput[]) {
+ inputs = (RemoteInput[]) tag;
+ }
+
+ if (inputs == null) {
+ return false;
+ }
+
+ RemoteInput input = null;
+
+ for (RemoteInput i : inputs) {
+ if (i.getAllowFreeFormInput()) {
+ input = i;
+ }
+ }
+
+ if (input == null) {
+ return false;
+ }
+
+ ViewParent p = view.getParent();
+ RemoteInputView riv = null;
+ while (p != null) {
+ if (p instanceof View) {
+ View pv = (View) p;
+ if (pv.isRootNamespace()) {
+ riv = findRemoteInputView(pv);
+ break;
+ }
+ }
+ p = p.getParent();
+ }
+ ExpandableNotificationRow row = null;
+ while (p != null) {
+ if (p instanceof ExpandableNotificationRow) {
+ row = (ExpandableNotificationRow) p;
+ break;
+ }
+ p = p.getParent();
+ }
+
+ if (row == null) {
+ return false;
+ }
+
+ row.setUserExpanded(true);
+
+ if (!mLockscreenUserManager.shouldAllowLockscreenRemoteInput()) {
+ final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
+ if (mLockscreenUserManager.isLockscreenPublicMode(userId)) {
+ mCallback.onLockedRemoteInput(row, view);
+ return true;
+ }
+ if (mUserManager.getUserInfo(userId).isManagedProfile()
+ && mPresenter.isDeviceLocked(userId)) {
+ mCallback.onLockedWorkRemoteInput(userId, row, view);
+ return true;
+ }
+ }
+
+ if (riv == null) {
+ riv = findRemoteInputView(row.getPrivateLayout().getExpandedChild());
+ if (riv == null) {
+ return false;
+ }
+ if (!row.getPrivateLayout().getExpandedChild().isShown()) {
+ mCallback.onMakeExpandedVisibleForRemoteInput(row, view);
+ return true;
+ }
+ }
+
+ int width = view.getWidth();
+ if (view instanceof TextView) {
+ // Center the reveal on the text which might be off-center from the TextView
+ TextView tv = (TextView) view;
+ if (tv.getLayout() != null) {
+ int innerWidth = (int) tv.getLayout().getLineWidth(0);
+ innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight();
+ width = Math.min(width, innerWidth);
+ }
+ }
+ int cx = view.getLeft() + width / 2;
+ int cy = view.getTop() + view.getHeight() / 2;
+ int w = riv.getWidth();
+ int h = riv.getHeight();
+ int r = Math.max(
+ Math.max(cx + cy, cx + (h - cy)),
+ Math.max((w - cx) + cy, (w - cx) + (h - cy)));
+
+ riv.setRevealParameters(cx, cy, r);
+ riv.setPendingIntent(pendingIntent);
+ riv.setRemoteInput(inputs, input);
+ riv.focusAnimated();
+
+ return true;
+ }
+
+ private RemoteInputView findRemoteInputView(View v) {
+ if (v == null) {
+ return null;
+ }
+ return (RemoteInputView) v.findViewWithTag(RemoteInputView.VIEW_TAG);
+ }
+ };
+
+ public NotificationRemoteInputManager(NotificationLockscreenUserManager lockscreenUserManager,
+ Context context) {
+ mLockscreenUserManager = lockscreenUserManager;
+ mContext = context;
+ mBarService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ }
+
+ public void setUpWithPresenter(NotificationPresenter presenter,
+ Callback callback,
+ RemoteInputController.Delegate delegate) {
+ mPresenter = presenter;
+ mCallback = callback;
+ mRemoteInputController = new RemoteInputController(delegate);
+ mRemoteInputController.addCallback(new RemoteInputController.Callback() {
+ @Override
+ public void onRemoteInputSent(NotificationData.Entry entry) {
+ if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(entry.key)) {
+ mPresenter.removeNotification(entry.key, null);
+ } else if (mRemoteInputEntriesToRemoveOnCollapse.contains(entry)) {
+ // We're currently holding onto this notification, but from the apps point of
+ // view it is already canceled, so we'll need to cancel it on the apps behalf
+ // after sending - unless the app posts an update in the mean time, so wait a
+ // bit.
+ mPresenter.getHandler().postDelayed(() -> {
+ if (mRemoteInputEntriesToRemoveOnCollapse.remove(entry)) {
+ mPresenter.removeNotification(entry.key, null);
+ }
+ }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY);
+ }
+ }
+ });
+
+ }
+
+ public RemoteInputController getController() {
+ return mRemoteInputController;
+ }
+
+ public void onUpdateNotification(NotificationData.Entry entry) {
+ mRemoteInputEntriesToRemoveOnCollapse.remove(entry);
+ }
+
+ /**
+ * Returns true if NotificationRemoteInputManager wants to keep this notification around.
+ *
+ * @param entry notification being removed
+ */
+ public boolean onRemoveNotification(NotificationData.Entry entry) {
+ if (entry != null && mRemoteInputController.isRemoteInputActive(entry)
+ && (entry.row != null && !entry.row.isDismissed())) {
+ mRemoteInputEntriesToRemoveOnCollapse.add(entry);
+ return true;
+ }
+ return false;
+ }
+
+ public void onPerformRemoveNotification(StatusBarNotification n,
+ NotificationData.Entry entry) {
+ if (mRemoteInputController.isRemoteInputActive(entry)) {
+ mRemoteInputController.removeRemoteInput(entry, null);
+ }
+ if (FORCE_REMOTE_INPUT_HISTORY
+ && mKeysKeptForRemoteInput.contains(n.getKey())) {
+ mKeysKeptForRemoteInput.remove(n.getKey());
+ }
+ }
+
+ public void removeRemoteInputEntriesKeptUntilCollapsed() {
+ for (int i = 0; i < mRemoteInputEntriesToRemoveOnCollapse.size(); i++) {
+ NotificationData.Entry entry = mRemoteInputEntriesToRemoveOnCollapse.valueAt(i);
+ mRemoteInputController.removeRemoteInput(entry, null);
+ mPresenter.removeNotification(entry.key, mPresenter.getLatestRankingMap());
+ }
+ mRemoteInputEntriesToRemoveOnCollapse.clear();
+ }
+
+ public void checkRemoteInputOutside(MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
+ && event.getX() == 0 && event.getY() == 0 // a touch outside both bars
+ && mRemoteInputController.isRemoteInputActive()) {
+ mRemoteInputController.closeRemoteInputs();
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("NotificationRemoteInputManager state:");
+ pw.print(" mRemoteInputEntriesToRemoveOnCollapse: ");
+ pw.println(mRemoteInputEntriesToRemoveOnCollapse);
+ pw.print(" mKeysKeptForRemoteInput: ");
+ pw.println(mKeysKeptForRemoteInput);
+ }
+
+ public void bindRow(ExpandableNotificationRow row) {
+ row.setRemoteInputController(mRemoteInputController);
+ row.setRemoteViewClickHandler(mOnClickHandler);
+ }
+
+ public Set<String> getKeysKeptForRemoteInput() {
+ return mKeysKeptForRemoteInput;
+ }
+
+ @VisibleForTesting
+ public Set<NotificationData.Entry> getRemoteInputEntriesToRemoveOnCollapse() {
+ return mRemoteInputEntriesToRemoveOnCollapse;
+ }
+
+ /**
+ * Callback for various remote input related events, or for providing information that
+ * NotificationRemoteInputManager needs to know to decide what to do.
+ */
+ public interface Callback {
+
+ /**
+ * Called when remote input was activated but the device is locked.
+ *
+ * @param row
+ * @param clicked
+ */
+ void onLockedRemoteInput(ExpandableNotificationRow row, View clicked);
+
+ /**
+ * Called when remote input was activated but the device is locked and in a managed profile.
+ *
+ * @param userId
+ * @param row
+ * @param clicked
+ */
+ void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row, View clicked);
+
+ /**
+ * Called when a row should be made expanded for the purposes of remote input.
+ *
+ * @param row
+ * @param clickedView
+ */
+ void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row, View clickedView);
+
+ /**
+ * Return whether or not remote input should be handled for this view.
+ *
+ * @param view
+ * @param pendingIntent
+ * @return true iff the remote input should be handled
+ */
+ boolean shouldHandleRemoteInput(View view, PendingIntent pendingIntent);
+
+ /**
+ * Performs any special handling for a remote view click. The default behaviour can be
+ * called through the defaultHandler parameter.
+ *
+ * @param view
+ * @param pendingIntent
+ * @param fillInIntent
+ * @param defaultHandler
+ * @return true iff the click was handled
+ */
+ boolean handleRemoteViewClick(View view, PendingIntent pendingIntent, Intent fillInIntent,
+ ClickHandler defaultHandler);
+ }
+
+ /**
+ * Helper interface meant for passing the default on click behaviour to NotificationPresenter,
+ * so it may do its own handling before invoking the default behaviour.
+ */
+ public interface ClickHandler {
+ /**
+ * Tries to handle a click on a remote view.
+ *
+ * @return true iff the click was handled
+ */
+ boolean handleClick();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index b7a00eb..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,6 @@
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) {
@@ -102,9 +99,6 @@
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();
@@ -112,15 +106,6 @@
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;
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 ff6c775..97e3d22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -21,17 +21,24 @@
import com.android.systemui.statusbar.phone.StatusBarWindowManager;
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<>();
@@ -45,6 +52,53 @@
}
/**
+ * 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
+ }
+ }
+ }
+
+ /**
* Adds a currently active remote input.
*
* @param entry the entry for which a remote input is now active.
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/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/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 3f57c2f..50cbd69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -119,6 +119,28 @@
return mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT);
}
+ /**
+ * Some screens need to be completely black before changing the display power mode,
+ * unexpected behavior might happen if this parameter isn't respected.
+ *
+ * @return true if screen needs to be completely black before a power transition.
+ */
+ public boolean getDisplayNeedsBlanking() {
+ return mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_displayBlanksAfterDoze);
+ }
+
+ /**
+ * Whether we can implement our own screen off animation or if we need
+ * to rely on DisplayPowerManager to dim the display.
+ *
+ * @return true if SystemUI can control the screen off animation.
+ */
+ public boolean getCanControlScreenOffAnimation() {
+ return !mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_dozeAfterScreenOff);
+ }
+
private boolean getBoolean(String propName, int resId) {
return SystemProperties.getBoolean(propName, mContext.getResources().getBoolean(resId));
}
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 80d4061..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;
@@ -266,7 +266,6 @@
}
private void showBouncer() {
- mScrimController.transitionTo(ScrimState.BOUNCER);
mStatusBarKeyguardViewManager.animateCollapsePanels(
FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
mPendingShowBouncer = false;
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/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 836efff..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() {
@@ -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 17e3599..61dd22f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -506,7 +506,8 @@
if (suppressedSummary) {
continue;
}
- if (!mStatusBar.shouldShowOnKeyguard(row.getStatusBarNotification())) {
+ if (!mStatusBar.getNotificationLockscreenUserManager().shouldShowOnKeyguard(
+ row.getStatusBarNotification())) {
continue;
}
if (row.isRemoved()) {
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 dfd4c17..168758f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -195,6 +195,10 @@
public void transitionTo(ScrimState state, Callback callback) {
if (state == mState) {
+ // Call the callback anyway, unless it's already enqueued
+ if (callback != null && mCallback != callback) {
+ callback.onFinished();
+ }
return;
} else if (DEBUG) {
Log.d(TAG, "State changed to: " + state);
@@ -204,12 +208,15 @@
throw new IllegalArgumentException("Cannot change to UNINITIALIZED.");
}
+ final ScrimState oldState = mState;
+ mState = state;
+
if (mCallback != null) {
mCallback.onCancelled();
}
mCallback = callback;
- state.prepare(mState);
+ state.prepare(oldState);
mScreenBlankingCallbackCalled = false;
mAnimationDelay = 0;
mBlankScreen = state.getBlanksScreen();
@@ -228,8 +235,6 @@
mKeyguardFadeoutAnimation.cancel();
}
- mState = state;
-
// Do not let the device sleep until we're done with all animations
if (!mWakeLockHeld) {
if (mWakeLock != null) {
@@ -310,7 +315,6 @@
mCurrentInFrontAlpha = 0;
}
} else {
- Log.w(TAG, "Invalid state, cannot set panel expansion when: " + mState);
return;
}
@@ -629,6 +633,11 @@
}
}
+ // 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
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 0db98f3..c33cc50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -20,6 +20,7 @@
import android.os.Trace;
import com.android.systemui.statusbar.ScrimView;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
* Possible states of the ScrimController state machine.
@@ -38,12 +39,18 @@
@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;
+ mBlankScreen = false;
if (previousState == ScrimState.AOD) {
- updateScrimColor(mScrimInFront, 1, Color.BLACK);
+ mAnimationDuration = StackStateAnimator.ANIMATION_DURATION_WAKEUP;
+ if (mDisplayRequiresBlanking) {
+ // 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 = true;
+ updateScrimColor(mScrimInFront, 1, Color.BLACK);
+ }
+ } else {
+ mAnimationDuration = ScrimController.ANIMATION_DURATION;
}
mCurrentBehindAlpha = mScrimBehindAlphaKeyguard;
mCurrentInFrontAlpha = 0;
@@ -78,7 +85,7 @@
AOD {
@Override
public void prepare(ScrimState previousState) {
- if (previousState == ScrimState.PULSING) {
+ if (previousState == ScrimState.PULSING && !mCanControlScreenOff) {
updateScrimColor(mScrimInFront, 1, Color.BLACK);
}
final boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn();
@@ -89,7 +96,7 @@
mCurrentBehindTint = Color.BLACK;
// DisplayPowerManager will blank the screen for us, we just need
// to set our state.
- mAnimateChange = false;
+ mAnimateChange = mCanControlScreenOff;
}
},
@@ -103,8 +110,10 @@
mCurrentInFrontAlpha = 0;
mCurrentInFrontTint = Color.BLACK;
mCurrentBehindTint = Color.BLACK;
- mBlankScreen = true;
- updateScrimColor(mScrimInFront, 1, Color.BLACK);
+ mBlankScreen = mDisplayRequiresBlanking;
+ if (mDisplayRequiresBlanking) {
+ updateScrimColor(mScrimInFront, 1, Color.BLACK);
+ }
}
},
@@ -147,11 +156,15 @@
ScrimView mScrimInFront;
ScrimView mScrimBehind;
DozeParameters mDozeParameters;
+ boolean mDisplayRequiresBlanking;
+ boolean mCanControlScreenOff;
public void init(ScrimView scrimInFront, ScrimView scrimBehind, DozeParameters dozeParameters) {
mScrimInFront = scrimInFront;
mScrimBehind = scrimBehind;
mDozeParameters = dozeParameters;
+ mDisplayRequiresBlanking = dozeParameters.getDisplayNeedsBlanking();
+ mCanControlScreenOff = dozeParameters.getCanControlScreenOffAnimation();
}
public void prepare(ScrimState previousState) {
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 dc8100f..d162448 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,7 +24,13 @@
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.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
+import static com.android.systemui.statusbar.NotificationRemoteInputManager
+ .FORCE_REMOTE_INPUT_HISTORY;
import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
@@ -45,7 +50,6 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.app.RemoteInput;
import android.app.StatusBarManager;
import android.app.TaskStackBuilder;
import android.app.WallpaperColors;
@@ -108,7 +112,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;
@@ -125,9 +128,7 @@
import android.view.animation.AccelerateInterpolator;
import android.widget.DateTimeView;
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 +154,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,8 +201,11 @@
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.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.ScrimView;
@@ -229,7 +232,6 @@
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.policy.PreviewInflater;
-import com.android.systemui.statusbar.policy.RemoteInputView;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -238,7 +240,6 @@
.OnChildLocationsChangedListener;
import com.android.systemui.util.NotificationChannels;
import com.android.systemui.util.leak.LeakDetector;
-import com.android.systemui.util.wakelock.WakeLock;
import com.android.systemui.volume.VolumeComponent;
import java.io.FileDescriptor;
@@ -251,6 +252,7 @@
import java.util.List;
import java.util.Map;
import java.util.Stack;
+import java.util.function.Function;
public class StatusBar extends SystemUI implements DemoMode,
DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
@@ -261,13 +263,8 @@
ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter {
public static final boolean MULTIUSER_DEBUG = false;
- public static final boolean ENABLE_REMOTE_INPUT =
- SystemProperties.getBoolean("debug.enable_remote_input", true);
public static final boolean ENABLE_CHILD_NOTIFICATIONS
= 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;
@@ -278,7 +275,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";
@@ -289,8 +285,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;
@@ -348,14 +342,6 @@
private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
/**
- * How long to wait before auto-dismissing a notification that was kept for remote input, and
- * has now sent a remote input. We auto-dismiss, because the app may not see a reason to cancel
- * these given that they technically don't exist anymore. We wait a bit in case the app issues
- * an update.
- */
- private static final int REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY = 200;
-
- /**
* Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode
* won't draw anything and uninitialized memory will show through
* if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
@@ -380,8 +366,6 @@
*/
protected int mState;
protected boolean mBouncerShowing;
- protected boolean mShowLockscreenNotifications;
- protected boolean mAllowLockscreenRemoteInput;
private PhoneStatusBarPolicy mIconPolicy;
@@ -544,6 +528,8 @@
new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
private NotificationMediaManager mMediaManager;
+ protected NotificationLockscreenUserManager mLockscreenUserManager;
+ protected NotificationRemoteInputManager mRemoteInputManager;
/** Keys of notifications currently visible to the user. */
private final ArraySet<NotificationVisibility> mCurrentlyVisibleNotifications =
@@ -655,21 +641,19 @@
.Callback() {
@Override
public void onFinished() {
- notifyKeyguardState();
- }
-
- @Override
- public void onCancelled() {
- notifyKeyguardState();
- }
-
- private void notifyKeyguardState() {
if (mStatusBarKeyguardViewManager == null) {
Log.w(TAG, "Tried to notify keyguard visibility when "
+ "mStatusBarKeyguardViewManager was null");
return;
}
- mStatusBarKeyguardViewManager.onKeyguardFadedAway();
+ if (mKeyguardFadingAway) {
+ mStatusBarKeyguardViewManager.onKeyguardFadedAway();
+ }
+ }
+
+ @Override
+ public void onCancelled() {
+ onFinished();
}
};
@@ -731,6 +715,7 @@
@Override
public void start() {
+ mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
mNetworkController = Dependency.get(NetworkController.class);
mUserSwitcherController = Dependency.get(UserSwitcherController.class);
mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
@@ -742,6 +727,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);
@@ -777,37 +764,17 @@
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));
mRecents = getComponent(Recents.class);
- mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
mLockPatternUtils = new LockPatternUtils(mContext);
mMediaManager = new NotificationMediaManager(this, mContext);
+ mLockscreenUserManager.setUpWithPresenter(this);
// Connect in to the status bar manager service
mCommandQueue = getComponent(CommandQueue.class);
@@ -828,7 +795,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);
@@ -843,14 +809,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, mRemoteInputManager, mContext);
+ mNotificationListener.register();
if (DEBUG) {
Log.d(TAG, String.format(
@@ -863,29 +823,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));
@@ -899,7 +843,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) {
@@ -944,8 +887,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);
@@ -1209,7 +1151,7 @@
protected View.OnTouchListener getStatusBarWindowTouchListener() {
return (v, event) -> {
checkUserAutohide(event);
- checkRemoteInputOutside(event);
+ mRemoteInputManager.checkRemoteInputOutside(event);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mExpandedVisible) {
animateCollapsePanels();
@@ -1431,7 +1373,7 @@
}
}
try {
- mBarService.onClearAllNotifications(mCurrentUserId);
+ mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId());
} catch (Exception ex) {
}
});
@@ -1471,15 +1413,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);
@@ -1491,31 +1424,7 @@
mKeyguardIndicationController
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
- mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
-
- mRemoteInputController.addCallback(new RemoteInputController.Callback() {
- @Override
- public void onRemoteInputSent(Entry entry) {
- if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(entry.key)) {
- removeNotification(entry.key, null);
- } else if (mRemoteInputEntriesToRemoveOnCollapse.contains(entry)) {
- // We're currently holding onto this notification, but from the apps point of
- // view it is already canceled, so we'll need to cancel it on the apps behalf
- // after sending - unless the app posts an update in the mean time, so wait a
- // bit.
- mHandler.postDelayed(() -> {
- if (mRemoteInputEntriesToRemoveOnCollapse.remove(entry)) {
- removeNotification(entry.key, null);
- }
- }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY);
- }
- try {
- mBarService.onNotificationDirectReplied(entry.key);
- } catch (RemoteException e) {
- // system process is dead if we're here.
- }
- }
- });
+ mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager);
mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
mLightBarController.setFingerprintUnlockController(mFingerprintUnlockController);
@@ -1570,13 +1479,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)) {
@@ -1590,11 +1505,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 {
@@ -1671,7 +1586,8 @@
}
}
- protected void updateNotificationRanking(RankingMap ranking) {
+ @Override
+ public void updateNotificationRanking(RankingMap ranking) {
mNotificationData.updateRanking(ranking);
updateNotifications();
}
@@ -1685,7 +1601,7 @@
// sending look longer than it takes.
// Also we should not defer the removal if reordering isn't allowed since otherwise
// some notifications can't disappear before the panel is closed.
- boolean ignoreEarliestRemovalTime = mRemoteInputController.isSpinning(key)
+ boolean ignoreEarliestRemovalTime = mRemoteInputManager.getController().isSpinning(key)
&& !FORCE_REMOTE_INPUT_HISTORY
|| !mVisualStabilityManager.isReorderingAllowed();
deferRemoval = !mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime);
@@ -1693,7 +1609,7 @@
mMediaManager.onNotificationRemoved(key);
Entry entry = mNotificationData.get(key);
- if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)
+ if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputManager.getController().isSpinning(key)
&& entry.row != null && !entry.row.isDismissed()) {
StatusBarNotification sbn = entry.notification;
@@ -1724,14 +1640,14 @@
newNotification, sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
boolean updated = false;
try {
- updateNotification(newSbn, null);
+ updateNotificationInternal(newSbn, null);
updated = true;
} catch (InflationException e) {
deferRemoval = false;
}
if (updated) {
Log.w(TAG, "Keeping notification around after sending remote input "+ entry.key);
- mKeysKeptForRemoteInput.add(entry.key);
+ mRemoteInputManager.getKeysKeptForRemoteInput().add(entry.key);
return;
}
}
@@ -1741,12 +1657,11 @@
return;
}
- if (entry != null && mRemoteInputController.isRemoteInputActive(entry)
- && (entry.row != null && !entry.row.isDismissed())) {
+ if (mRemoteInputManager.onRemoveNotification(entry)) {
mLatestRankingMap = ranking;
- mRemoteInputEntriesToRemoveOnCollapse.add(entry);
return;
}
+
if (entry != null && mGutsManager.getExposedGuts() != null
&& mGutsManager.getExposedGuts() == entry.row.getGuts()
&& entry.row.getGuts() != null && !entry.row.getGuts().isLeavebehind()) {
@@ -1820,9 +1735,7 @@
protected void performRemoveNotification(StatusBarNotification n) {
Entry entry = mNotificationData.get(n.getKey());
- if (mRemoteInputController.isRemoteInputActive(entry)) {
- mRemoteInputController.removeRemoteInput(entry, null);
- }
+ mRemoteInputManager.onPerformRemoveNotification(n, entry);
// start old BaseStatusBar.performRemoveNotification.
final String pkg = n.getPackageName();
final String tag = n.getTag();
@@ -1835,12 +1748,7 @@
} else if (mStackScroller.hasPulsingNotifications()) {
dismissalSurface = NotificationStats.DISMISSAL_AOD;
}
- mBarService.onNotificationClear(pkg, tag, id, userId, n.getKey(),
- dismissalSurface);
- if (FORCE_REMOTE_INPUT_HISTORY
- && mKeysKeptForRemoteInput.contains(n.getKey())) {
- mKeysKeptForRemoteInput.remove(n.getKey());
- }
+ mBarService.onNotificationClear(pkg, tag, id, userId, n.getKey(), dismissalSurface);
removeNotification(n.getKey(), null);
} catch (RemoteException ex) {
@@ -1876,12 +1784,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())) {
@@ -1973,21 +1886,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
@@ -2090,9 +1988,6 @@
mQSPanel.clickTile(tile);
}
- private boolean packageHasVisibilityOverride(String key) {
- return mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_PRIVATE;
- }
private void updateClearAll() {
if (!mClearAllEnabled) {
@@ -2572,7 +2467,7 @@
mStatusBarWindowManager.setHeadsUpShowing(false);
mHeadsUpManager.setHeadsUpGoingAway(false);
}
- removeRemoteInputEntriesKeptUntilCollapsed();
+ mRemoteInputManager.removeRemoteInputEntriesKeptUntilCollapsed();
});
}
}
@@ -2651,19 +2546,10 @@
}
if (!isExpanded) {
- removeRemoteInputEntriesKeptUntilCollapsed();
+ mRemoteInputManager.removeRemoteInputEntriesKeptUntilCollapsed();
}
}
- private void removeRemoteInputEntriesKeptUntilCollapsed() {
- for (int i = 0; i < mRemoteInputEntriesToRemoveOnCollapse.size(); i++) {
- Entry entry = mRemoteInputEntriesToRemoveOnCollapse.valueAt(i);
- mRemoteInputController.removeRemoteInput(entry, null);
- removeNotification(entry.key, mLatestRankingMap);
- }
- mRemoteInputEntriesToRemoveOnCollapse.clear();
- }
-
public NotificationStackScrollLayout getNotificationScrollLayout() {
return mStackScroller;
}
@@ -2694,7 +2580,7 @@
OverlayInfo themeInfo = null;
try {
themeInfo = mOverlayManager.getOverlayInfo("com.android.systemui.theme.dark",
- mCurrentUserId);
+ mLockscreenUserManager.getCurrentUserId());
} catch (RemoteException e) {
e.printStackTrace();
}
@@ -3247,19 +3133,12 @@
if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed
&& event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
&& event.getX() == 0 && event.getY() == 0 // a touch outside both bars
- && !mRemoteInputController.isRemoteInputActive()) { // not due to typing in IME
+ && !mRemoteInputManager.getController()
+ .isRemoteInputActive()) { // not due to typing in IME
userAutohide();
}
}
- private void checkRemoteInputOutside(MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
- && event.getX() == 0 && event.getY() == 0 // a touch outside both bars
- && mRemoteInputController.isRemoteInputActive()) {
- mRemoteInputController.closeRemoteInputs();
- }
- }
-
private void userAutohide() {
cancelAutohide();
mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear
@@ -3333,13 +3212,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());
}
@@ -3442,18 +3319,18 @@
private void addStatusBarWindow() {
makeStatusBarView();
mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
- 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();
- }
+ mRemoteInputManager.setUpWithPresenter(this, this, 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());
}
@@ -3484,7 +3361,7 @@
if (onlyProvisioned && !isDeviceProvisioned()) return;
final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
- mContext, intent, mCurrentUserId);
+ mContext, intent, mLockscreenUserManager.getCurrentUserId());
Runnable runnable = () -> {
mAssistManager.hideAssist();
intent.setFlags(
@@ -3573,10 +3450,10 @@
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
KeyboardShortcuts.dismiss();
- if (mRemoteInputController != null) {
- mRemoteInputController.closeRemoteInputs();
+ if (mRemoteInputManager.getController() != null) {
+ mRemoteInputManager.getController().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)) {
@@ -3668,7 +3545,8 @@
mScreenPinningRequest.onConfigurationChanged();
}
- public void userSwitched(int newUserId) {
+ @Override
+ public void onUserSwitched(int newUserId) {
// Begin old BaseStatusBar.userSwitched
setHeadsUpUser(newUserId);
// End old BaseStatusBar.userSwitched
@@ -3685,6 +3563,11 @@
setLockscreenUser(newUserId);
}
+ @Override
+ public NotificationLockscreenUserManager getNotificationLockscreenUserManager() {
+ return mLockscreenUserManager;
+ }
+
protected void setLockscreenUser(int newUserId) {
mLockscreenWallpaper.setCurrentUser(newUserId);
mScrimController.setCurrentUser(newUserId);
@@ -3757,23 +3640,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() {
@@ -3809,21 +3704,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
@@ -3931,7 +3828,8 @@
public void destroy() {
// Begin old BaseStatusBar.destroy().
- mContext.unregisterReceiver(mBaseBroadcastReceiver);
+ mContext.unregisterReceiver(mBannerActionBroadcastReceiver);
+ mLockscreenUserManager.destroy();
try {
mNotificationListener.unregisterAsSystemService();
} catch (RemoteException e) {
@@ -4185,14 +4083,10 @@
.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();
+ .withEndAction(()-> {
+ hideKeyguard();
+ mStatusBarKeyguardViewManager.onKeyguardFadedAway();
+ }).start();
}
/**
@@ -4337,18 +4231,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
@@ -4358,7 +4255,7 @@
isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
}
}
- setLockscreenPublicMode(isProfilePublic, userId);
+ mLockscreenUserManager.setLockscreenPublicMode(isProfilePublic, userId);
}
}
@@ -4416,7 +4313,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);
}
@@ -4454,7 +4351,8 @@
private void updateDozingState() {
Trace.traceCounter(Trace.TRACE_TAG_APP, "dozing", mDozing ? 1 : 0);
Trace.beginSection("StatusBar#updateDozingState");
- boolean animate = !mDozing && mDozeServiceHost.shouldAnimateWakeup();
+ boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup())
+ || (mDozing && mDozeServiceHost.shouldAnimateScreenOff());
mNotificationPanel.setDozing(mDozing, animate);
mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation);
mDozeScrimController.setDozing(mDozing);
@@ -4468,7 +4366,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);
@@ -4591,7 +4489,7 @@
clearNotificationEffects();
}
if (state == StatusBarState.KEYGUARD) {
- removeRemoteInputEntriesKeptUntilCollapsed();
+ mRemoteInputManager.removeRemoteInputEntriesKeptUntilCollapsed();
maybeEscalateHeadsUp();
}
mState = state;
@@ -4762,7 +4660,7 @@
return;
}
- int userId = mCurrentUserId;
+ int userId = mLockscreenUserManager.getCurrentUserId();
ExpandableNotificationRow row = null;
if (expandView instanceof ExpandableNotificationRow) {
row = (ExpandableNotificationRow) expandView;
@@ -4774,9 +4672,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;
@@ -4793,13 +4693,15 @@
dismissKeyguardThenExecute(dismissAction, true /* afterKeyguardGone */);
}
- protected void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
+ @Override
+ public void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
mLeaveOpenOnKeyguardHide = true;
showBouncer();
mPendingRemoteInputView = clicked;
}
- protected void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row,
+ @Override
+ public void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row,
View clickedView) {
if (isKeyguardShowing()) {
onLockedRemoteInput(row, clickedView);
@@ -4809,6 +4711,47 @@
}
}
+ @Override
+ public boolean shouldHandleRemoteInput(View view, PendingIntent pendingIntent) {
+ // Skip remote input as doing so will expand the notification shade.
+ return (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0;
+ }
+
+ @Override
+ public boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
+ Intent fillInIntent, NotificationRemoteInputManager.ClickHandler defaultHandler) {
+ final boolean isActivity = pendingIntent.isActivity();
+ if (isActivity) {
+ final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
+ mContext, pendingIntent.getIntent(), mLockscreenUserManager.getCurrentUserId());
+ dismissKeyguardThenExecute(() -> {
+ try {
+ ActivityManager.getService().resumeAppSwitches();
+ } catch (RemoteException e) {
+ }
+
+ boolean handled = defaultHandler.handleClick();
+
+ // close the shade if it was open
+ if (handled && !mNotificationPanel.isFullyCollapsed()) {
+ animateCollapsePanels(
+ CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
+ visibilityChanged(false);
+ mAssistManager.hideAssist();
+
+ // Wait for activity start.
+ return true;
+ } else {
+ return false;
+ }
+
+ }, afterKeyguardGone);
+ return true;
+ } else {
+ return defaultHandler.handleClick();
+ }
+ }
+
protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
String notificationKey) {
// Clear pending remote view, as we do not want to trigger pending remote input view when
@@ -4845,7 +4788,8 @@
// End old BaseStatusBar.startWorkChallengeIfNecessary.
}
- protected void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row,
+ @Override
+ public void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row,
View clicked) {
// Collapse notification and show work challenge
animateCollapsePanels();
@@ -4855,19 +4799,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;
@@ -5078,6 +5015,7 @@
return !mNotificationData.getActiveNotifications().isEmpty();
}
+ @Override
public void wakeUpIfDozing(long time, View where) {
if (mDozing) {
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -5092,6 +5030,11 @@
}
@Override
+ public boolean isDeviceLocked(int userId) {
+ return mKeyguardManager.isDeviceLocked(userId);
+ }
+
+ @Override
public void appTransitionCancelled() {
EventBus.getDefault().send(new AppTransitionFinishedEvent());
}
@@ -5147,12 +5090,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;
}
@@ -5171,6 +5116,7 @@
public void notifyFpAuthModeChanged() {
updateDozing();
+ updateScrimController();
}
private void updateDozing() {
@@ -5195,7 +5141,15 @@
Trace.endSection();
}
- public void updateScrimController() {
+ @VisibleForTesting
+ void updateScrimController() {
+ Trace.beginSection("StatusBar#updateScrimController");
+
+ // We don't want to end up in KEYGUARD state when we're unlocking with
+ // fingerprint from doze. We should cross fade directly from black.
+ final boolean wakeAndUnlocking = mFingerprintUnlockController.getMode()
+ == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
+
if (mBouncerShowing) {
mScrimController.transitionTo(ScrimState.BOUNCER);
} else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) {
@@ -5206,11 +5160,12 @@
// Handled in DozeScrimController#setPulsing
} else if (mDozing) {
mScrimController.transitionTo(ScrimState.AOD);
- } else if (mIsKeyguard) {
+ } else if (mIsKeyguard && !wakeAndUnlocking) {
mScrimController.transitionTo(ScrimState.KEYGUARD);
} else {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
}
+ Trace.endSection();
}
public boolean isKeyguardShowing() {
@@ -5224,6 +5179,7 @@
private final class DozeServiceHost implements DozeHost {
private final ArrayList<Callback> mCallbacks = new ArrayList<>();
private boolean mAnimateWakeup;
+ private boolean mAnimateScreenOff;
private boolean mIgnoreTouchWhilePulsing;
@Override
@@ -5371,6 +5327,11 @@
}
@Override
+ public void setAnimateScreenOff(boolean animateScreenOff) {
+ mAnimateScreenOff = animateScreenOff;
+ }
+
+ @Override
public void onDoubleTap(float screenX, float screenY) {
if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null
&& mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
@@ -5414,6 +5375,10 @@
private boolean shouldAnimateWakeup() {
return mAnimateWakeup;
}
+
+ public boolean shouldAnimateScreenOff() {
+ return mAnimateScreenOff;
+ }
}
public boolean shouldIgnoreTouch() {
@@ -5431,7 +5396,6 @@
protected final NotificationGroupManager mGroupManager = new NotificationGroupManager();
- protected RemoteInputController mRemoteInputController;
// for heads up notifications
protected HeadsUpManager mHeadsUpManager;
@@ -5441,8 +5405,6 @@
// handling reordering
protected final VisualStabilityManager mVisualStabilityManager = new VisualStabilityManager();
- protected int mCurrentUserId = 0;
- final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
protected AccessibilityManager mAccessibilityManager;
@@ -5450,14 +5412,6 @@
protected boolean mVisible;
protected final ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
- protected final ArraySet<Entry> mRemoteInputEntriesToRemoveOnCollapse = new ArraySet<>();
-
- /**
- * Notifications with keys in this set are not actually around anymore. We kept them 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.
- */
- protected final ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
// mScreenOnFromKeyguard && mVisible.
private boolean mVisibleToUser;
@@ -5469,13 +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;
private LockPatternUtils mLockPatternUtils;
private DeviceProvisionedController mDeviceProvisionedController
@@ -5491,8 +5438,6 @@
protected RecentsComponent mRecents;
- protected int mZenMode;
-
protected NotificationShelf mNotificationShelf;
protected DismissView mDismissView;
protected EmptyShadeView mEmptyShadeView;
@@ -5531,280 +5476,15 @@
}
};
- 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
- public boolean onClickHandler(
- final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
- wakeUpIfDozing(SystemClock.uptimeMillis(), view);
-
- if (handleRemoteInput(view, pendingIntent)) {
- return true;
- }
-
- if (DEBUG) {
- Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
- }
- logActionClick(view);
- // The intent we are sending is for the application, which
- // won't have permission to immediately start an activity after
- // the user switches to home. We know it is safe to do at this
- // point, so make sure new activity switches are now allowed.
- try {
- ActivityManager.getService().resumeAppSwitches();
- } catch (RemoteException e) {
- }
- final boolean isActivity = pendingIntent.isActivity();
- if (isActivity) {
- final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
- mContext, pendingIntent.getIntent(), mCurrentUserId);
- dismissKeyguardThenExecute(() -> {
- try {
- ActivityManager.getService().resumeAppSwitches();
- } catch (RemoteException e) {
- }
-
- boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
-
- // close the shade if it was open
- if (handled && !mNotificationPanel.isFullyCollapsed()) {
- animateCollapsePanels(
- CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
- visibilityChanged(false);
- mAssistManager.hideAssist();
-
- // Wait for activity start.
- return true;
- } else {
- return false;
- }
-
- }, afterKeyguardGone);
- return true;
- } else {
- return superOnClickHandler(view, pendingIntent, fillInIntent);
- }
- }
-
- private void logActionClick(View view) {
- ViewParent parent = view.getParent();
- String key = getNotificationKeyForParent(parent);
- if (key == null) {
- Log.w(TAG, "Couldn't determine notification for click.");
- return;
- }
- int index = -1;
- // If this is a default template, determine the index of the button.
- if (view.getId() == com.android.internal.R.id.action0 &&
- parent != null && parent instanceof ViewGroup) {
- ViewGroup actionGroup = (ViewGroup) parent;
- index = actionGroup.indexOfChild(view);
- }
- try {
- mBarService.onNotificationActionClick(key, index);
- } catch (RemoteException e) {
- // Ignore
- }
- }
-
- private String getNotificationKeyForParent(ViewParent parent) {
- while (parent != null) {
- if (parent instanceof ExpandableNotificationRow) {
- return ((ExpandableNotificationRow) parent).getStatusBarNotification().getKey();
- }
- parent = parent.getParent();
- }
- return null;
- }
-
- private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
- Intent fillInIntent) {
- return super.onClickHandler(view, pendingIntent, fillInIntent,
- WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
- }
-
- private boolean handleRemoteInput(View view, PendingIntent pendingIntent) {
- if ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
- // Skip remote input as doing so will expand the notification shade.
- return true;
- }
-
- Object tag = view.getTag(com.android.internal.R.id.remote_input_tag);
- RemoteInput[] inputs = null;
- if (tag instanceof RemoteInput[]) {
- inputs = (RemoteInput[]) tag;
- }
-
- if (inputs == null) {
- return false;
- }
-
- RemoteInput input = null;
-
- for (RemoteInput i : inputs) {
- if (i.getAllowFreeFormInput()) {
- input = i;
- }
- }
-
- if (input == null) {
- return false;
- }
-
- ViewParent p = view.getParent();
- RemoteInputView riv = null;
- while (p != null) {
- if (p instanceof View) {
- View pv = (View) p;
- if (pv.isRootNamespace()) {
- riv = findRemoteInputView(pv);
- break;
- }
- }
- p = p.getParent();
- }
- ExpandableNotificationRow row = null;
- while (p != null) {
- if (p instanceof ExpandableNotificationRow) {
- row = (ExpandableNotificationRow) p;
- break;
- }
- p = p.getParent();
- }
-
- if (row == null) {
- return false;
- }
-
- row.setUserExpanded(true);
-
- if (!mAllowLockscreenRemoteInput) {
- final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
- if (isLockscreenPublicMode(userId)) {
- onLockedRemoteInput(row, view);
- return true;
- }
- if (mUserManager.getUserInfo(userId).isManagedProfile()
- && mKeyguardManager.isDeviceLocked(userId)) {
- onLockedWorkRemoteInput(userId, row, view);
- return true;
- }
- }
-
- if (riv == null) {
- riv = findRemoteInputView(row.getPrivateLayout().getExpandedChild());
- if (riv == null) {
- return false;
- }
- if (!row.getPrivateLayout().getExpandedChild().isShown()) {
- onMakeExpandedVisibleForRemoteInput(row, view);
- return true;
- }
- }
-
- int width = view.getWidth();
- if (view instanceof TextView) {
- // Center the reveal on the text which might be off-center from the TextView
- TextView tv = (TextView) view;
- if (tv.getLayout() != null) {
- int innerWidth = (int) tv.getLayout().getLineWidth(0);
- innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight();
- width = Math.min(width, innerWidth);
- }
- }
- int cx = view.getLeft() + width / 2;
- int cy = view.getTop() + view.getHeight() / 2;
- int w = riv.getWidth();
- int h = riv.getHeight();
- int r = Math.max(
- Math.max(cx + cy, cx + (h - cy)),
- Math.max((w - cx) + cy, (w - cx) + (h - cy)));
-
- riv.setRevealParameters(cx, cy, r);
- riv.setPendingIntent(pendingIntent);
- riv.setRemoteInput(inputs, input);
- riv.focusAnimated();
-
- return true;
- }
-
- private RemoteInputView findRemoteInputView(View v) {
- if (v == null) {
- return null;
- }
- return (RemoteInputView) v.findViewWithTag(RemoteInputView.VIEW_TAG);
- }
- };
-
- 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);
@@ -5816,141 +5496,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(),
@@ -6006,9 +5556,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) {
@@ -6023,12 +5573,6 @@
}
}
- protected boolean isCurrentProfile(int userId) {
- synchronized (mCurrentProfiles) {
- return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
- }
- }
-
@Override
public NotificationGroupManager getGroupManager() {
return mGroupManager;
@@ -6115,89 +5659,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);
}
/**
@@ -6205,7 +5674,7 @@
*/
@Override // NotificationData.Environment
public boolean isSecurelyLocked(int userId) {
- return isLockscreenPublicMode(userId);
+ return mLockscreenUserManager.isLockscreenPublicMode(userId);
}
/**
@@ -6251,12 +5720,11 @@
row.setGroupManager(mGroupManager);
row.setHeadsUpManager(mHeadsUpManager);
row.setAboveShelfChangedListener(mAboveShelfObserver);
- row.setRemoteInputController(mRemoteInputController);
row.setOnExpandClickListener(this);
- row.setRemoteViewClickHandler(mOnClickHandler);
row.setInflationCallback(this);
row.setSecureStateProvider(this::isKeyguardCurrentlySecure);
row.setLongPressListener(getNotificationLongClicker());
+ mRemoteInputManager.bindRow(row);
// Get the app name.
// Note that Notification.Builder#bindHeaderAppName has similar logic
@@ -6286,7 +5754,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();
@@ -6318,57 +5786,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 {
@@ -6443,7 +5866,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.
@@ -6697,9 +6120,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 {
@@ -6749,49 +6174,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();
@@ -6801,7 +6186,8 @@
return;
}
mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
- mRemoteInputEntriesToRemoveOnCollapse.remove(entry);
+ mRemoteInputManager.onUpdateNotification(entry);
+
if (key.equals(mGutsManager.getKeyToRemoveOnGutsClosed())) {
mGutsManager.setKeyToRemoveOnGutsClosed(null);
Log.w(TAG, "Notification that was kept for guts was updated. " + key);
@@ -6841,6 +6227,15 @@
setAreThereNotifications();
}
+ @Override
+ public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
+ try {
+ updateNotificationInternal(notification, ranking);
+ } catch (InflationException e) {
+ handleInflationException(notification, e);
+ }
+ }
+
protected void notifyHeadsUpGoingToSleep() {
maybeEscalateHeadsUp();
}
@@ -6903,9 +6298,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;
}
@@ -7021,13 +6418,13 @@
}
@Override
- public int getCurrentUserId() {
- return mCurrentUserId;
+ public NotificationData getNotificationData() {
+ return mNotificationData;
}
@Override
- public NotificationData getNotificationData() {
- return mNotificationData;
+ public Handler getHandler() {
+ return mHandler;
}
@Override
@@ -7035,12 +6432,12 @@
return mLatestRankingMap;
}
- final NotificationInfo.CheckSaveListener mCheckSaveListener =
+ 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 ef05bbb..8504d8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -33,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;
@@ -380,8 +380,6 @@
mStatusBar.fadeKeyguardWhilePulsing();
wakeAndUnlockDejank();
} else {
- mFingerprintUnlockController.startKeyguardFadingAway();
- mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
boolean staying = mStatusBar.hideKeyguard();
if (!staying) {
mStatusBarWindowManager.setKeyguardFadingAway(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index ed96b41..b0b5b8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
+
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.Context;
@@ -156,7 +158,7 @@
private void applyFocusableFlag(State state) {
boolean panelFocusable = state.statusBarFocusable && state.panelExpanded;
if (state.bouncerShowing && (state.keyguardOccluded || state.keyguardNeedsInput)
- || StatusBar.ENABLE_REMOTE_INPUT && state.remoteInputActive) {
+ || ENABLE_REMOTE_INPUT && state.remoteInputActive) {
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
} else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
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/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/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/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/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index ebebfac..fe39a89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -624,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) {
@@ -3681,6 +3681,7 @@
mHideSensitiveNeedsAnimation = true;
mNeedsAnimation = true;
}
+ updateContentHeight();
requestChildrenUpdate();
}
}
@@ -4443,10 +4444,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/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index c060b08..7374f11 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()) {
@@ -440,7 +448,7 @@
childState.height = Math.max(row.getIntrinsicHeight(), childState.height);
childState.hidden = false;
ExpandableViewState topState = resultState.getViewStateForView(topHeadsUpEntry);
- if (!isTopEntry && (!mIsExpanded
+ if (topState != null && !isTopEntry && (!mIsExpanded
|| unmodifiedEndLocation < topState.yTranslation + topState.height)) {
// Ensure that a headsUp doesn't vertically extend further than the heads-up at
// the top most z-position
@@ -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/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index f78a718..236c348 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -40,7 +40,7 @@
public class StackStateAnimator {
public static final int ANIMATION_DURATION_STANDARD = 360;
- public static final int ANIMATION_DURATION_WAKEUP = 200;
+ public static final int ANIMATION_DURATION_WAKEUP = 500;
public static final int ANIMATION_DURATION_GO_TO_FULL_SHADE = 448;
public static final int ANIMATION_DURATION_APPEAR_DISAPPEAR = 464;
public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index 49a12f4..e1376ca 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -80,6 +80,7 @@
public static final int DISMISS_REASON_SETTINGS_CLICKED = 5;
public static final int DISMISS_REASON_DONE_CLICKED = 6;
public static final int DISMISS_STREAM_GONE = 7;
+ public static final int DISMISS_REASON_OUTPUT_CHOOSER = 8;
public static final String[] DISMISS_REASONS = {
"unknown",
"touch_outside",
@@ -88,7 +89,8 @@
"screen_off",
"settings_clicked",
"done_clicked",
- "a11y_stream_changed"
+ "a11y_stream_changed",
+ "output_chooser"
};
public static final int SHOW_REASON_UNKNOWN = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java
new file mode 100644
index 0000000..fa82e33
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2015 The Android Open 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 static com.android.settingslib.bluetooth.Utils.getBtClassDrawableWithDescription;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.settingslib.Utils;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.policy.BluetoothController;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class OutputChooserDialog extends SystemUIDialog
+ implements DialogInterface.OnDismissListener, OutputChooserLayout.Callback {
+
+ private static final String TAG = Util.logTag(OutputChooserDialog.class);
+ private static final int MAX_DEVICES = 10;
+
+ private final Context mContext;
+ private final BluetoothController mController;
+ private OutputChooserLayout mView;
+
+
+ public OutputChooserDialog(Context context) {
+ super(context);
+ mContext = context;
+ mController = Dependency.get(BluetoothController.class);
+
+ final IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ context.registerReceiver(mReceiver, filter);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.output_chooser);
+ setCanceledOnTouchOutside(true);
+ setOnDismissListener(this::onDismiss);
+ mView = findViewById(R.id.output_chooser);
+ mView.setCallback(this);
+ updateItems();
+ mController.addCallback(mCallback);
+ }
+
+ protected void cleanUp() {}
+
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ }
+
+ @Override
+ public void onDismiss(DialogInterface unused) {
+ mContext.unregisterReceiver(mReceiver);
+ mController.removeCallback(mCallback);
+ cleanUp();
+ }
+
+ @Override
+ public void onDetailItemClick(OutputChooserLayout.Item item) {
+ if (item == null || item.tag == null) return;
+ final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
+ if (device != null && device.getMaxConnectionState()
+ == BluetoothProfile.STATE_DISCONNECTED) {
+ mController.connect(device);
+ }
+ }
+
+ @Override
+ public void onDetailItemDisconnect(OutputChooserLayout.Item item) {
+ if (item == null || item.tag == null) return;
+ final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
+ if (device != null) {
+ mController.disconnect(device);
+ }
+ }
+
+ private void updateItems() {
+ if (mView == null) return;
+ if (mController.isBluetoothEnabled()) {
+ mView.setEmptyState(R.drawable.ic_qs_bluetooth_detail_empty,
+ R.string.quick_settings_bluetooth_detail_empty_text);
+ mView.setItemsVisible(true);
+ } else {
+ mView.setEmptyState(R.drawable.ic_qs_bluetooth_detail_empty,
+ R.string.bt_is_off);
+ mView.setItemsVisible(false);
+ }
+ ArrayList<OutputChooserLayout.Item> items = new ArrayList<>();
+ final Collection<CachedBluetoothDevice> devices = mController.getDevices();
+ if (devices != null) {
+ int connectedDevices = 0;
+ int count = 0;
+ for (CachedBluetoothDevice device : devices) {
+ if (mController.getBondState(device) == BluetoothDevice.BOND_NONE) continue;
+ final int majorClass = device.getBtClass().getMajorDeviceClass();
+ if (majorClass != BluetoothClass.Device.Major.AUDIO_VIDEO
+ && majorClass != BluetoothClass.Device.Major.UNCATEGORIZED) {
+ continue;
+ }
+ final OutputChooserLayout.Item item = new OutputChooserLayout.Item();
+ item.iconResId = R.drawable.ic_qs_bluetooth_on;
+ item.line1 = device.getName();
+ item.tag = device;
+ int state = device.getMaxConnectionState();
+ if (state == BluetoothProfile.STATE_CONNECTED) {
+ item.iconResId = R.drawable.ic_qs_bluetooth_connected;
+ int batteryLevel = device.getBatteryLevel();
+ if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
+ Pair<Drawable, String> pair =
+ getBtClassDrawableWithDescription(getContext(), device);
+ item.icon = pair.first;
+ item.line2 = mContext.getString(
+ R.string.quick_settings_connected_battery_level,
+ Utils.formatPercentage(batteryLevel));
+ } else {
+ item.line2 = mContext.getString(R.string.quick_settings_connected);
+ }
+ item.canDisconnect = true;
+ items.add(connectedDevices, item);
+ connectedDevices++;
+ } else if (state == BluetoothProfile.STATE_CONNECTING) {
+ item.iconResId = R.drawable.ic_qs_bluetooth_connecting;
+ item.line2 = mContext.getString(R.string.quick_settings_connecting);
+ items.add(connectedDevices, item);
+ } else {
+ items.add(item);
+ }
+ if (++count == MAX_DEVICES) {
+ break;
+ }
+ }
+ }
+ mView.setItems(items.toArray(new OutputChooserLayout.Item[items.size()]));
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+ if (D.BUG) Log.d(TAG, "Received ACTION_CLOSE_SYSTEM_DIALOGS");
+ cancel();
+ cleanUp();
+ }
+ }
+ };
+
+ private final BluetoothController.Callback mCallback = new BluetoothController.Callback() {
+ @Override
+ public void onBluetoothStateChange(boolean enabled) {
+ updateItems();
+ }
+
+ @Override
+ public void onBluetoothDevicesChanged() {
+ updateItems();
+ }
+ };
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserLayout.java b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserLayout.java
new file mode 100644
index 0000000..e8be4fd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserLayout.java
@@ -0,0 +1,258 @@
+/*
+ * 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.content.res.Configuration;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.FontSizeUtils;
+import com.android.systemui.R;
+import com.android.systemui.qs.AutoSizingList;
+
+/**
+ * Limited height list of devices.
+ */
+public class OutputChooserLayout extends FrameLayout {
+ private static final String TAG = "OutputChooserLayout";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private final int mQsDetailIconOverlaySize;
+ private final Context mContext;
+ private final H mHandler = new H();
+ private final Adapter mAdapter = new Adapter();
+
+ private String mTag;
+ private Callback mCallback;
+ private boolean mItemsVisible = true;
+ private AutoSizingList mItemList;
+ private View mEmpty;
+ private TextView mEmptyText;
+ private ImageView mEmptyIcon;
+
+ private Item[] mItems;
+
+ public OutputChooserLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ mTag = TAG;
+ mQsDetailIconOverlaySize = (int) getResources().getDimension(
+ R.dimen.qs_detail_icon_overlay_size);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mItemList = findViewById(android.R.id.list);
+ mItemList.setVisibility(GONE);
+ mItemList.setAdapter(mAdapter);
+ mEmpty = findViewById(android.R.id.empty);
+ mEmpty.setVisibility(GONE);
+ mEmptyText = mEmpty.findViewById(android.R.id.title);
+ mEmptyIcon = mEmpty.findViewById(android.R.id.icon);
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ FontSizeUtils.updateFontSize(mEmptyText, R.dimen.qs_detail_empty_text_size);
+ int count = mItemList.getChildCount();
+ for (int i = 0; i < count; i++) {
+ View item = mItemList.getChildAt(i);
+ FontSizeUtils.updateFontSize(item, android.R.id.title,
+ R.dimen.qs_detail_item_primary_text_size);
+ FontSizeUtils.updateFontSize(item, android.R.id.summary,
+ R.dimen.qs_detail_item_secondary_text_size);
+ }
+ }
+
+ public void setEmptyState(int icon, int text) {
+ mEmpty.post(() -> {
+ mEmptyIcon.setImageResource(icon);
+ mEmptyText.setText(text);
+ });
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (DEBUG) Log.d(mTag, "onAttachedToWindow");
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (DEBUG) Log.d(mTag, "onDetachedFromWindow");
+ mCallback = null;
+ }
+
+ public void setCallback(Callback callback) {
+ mHandler.removeMessages(H.SET_CALLBACK);
+ mHandler.obtainMessage(H.SET_CALLBACK, callback).sendToTarget();
+ }
+
+ public void setItems(Item[] items) {
+ mHandler.removeMessages(H.SET_ITEMS);
+ mHandler.obtainMessage(H.SET_ITEMS, items).sendToTarget();
+ }
+
+ public void setItemsVisible(boolean visible) {
+ mHandler.removeMessages(H.SET_ITEMS_VISIBLE);
+ mHandler.obtainMessage(H.SET_ITEMS_VISIBLE, visible ? 1 : 0, 0).sendToTarget();
+ }
+
+ private void handleSetCallback(Callback callback) {
+ mCallback = callback;
+ }
+
+ private void handleSetItems(Item[] items) {
+ final int itemCount = items != null ? items.length : 0;
+ mEmpty.setVisibility(itemCount == 0 ? VISIBLE : GONE);
+ mItemList.setVisibility(itemCount == 0 ? GONE : VISIBLE);
+ mItems = items;
+ mAdapter.notifyDataSetChanged();
+ }
+
+ private void handleSetItemsVisible(boolean visible) {
+ if (mItemsVisible == visible) return;
+ mItemsVisible = visible;
+ for (int i = 0; i < mItemList.getChildCount(); i++) {
+ mItemList.getChildAt(i).setVisibility(mItemsVisible ? VISIBLE : INVISIBLE);
+ }
+ }
+
+ private class Adapter extends BaseAdapter {
+
+ @Override
+ public int getCount() {
+ return mItems != null ? mItems.length : 0;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mItems[position];
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return 0;
+ }
+
+ @Override
+ public View getView(int position, View view, ViewGroup parent) {
+ final Item item = mItems[position];
+ if (view == null) {
+ view = LayoutInflater.from(mContext).inflate(R.layout.output_chooser_item, parent,
+ false);
+ }
+ view.setVisibility(mItemsVisible ? VISIBLE : INVISIBLE);
+ final ImageView iv = view.findViewById(android.R.id.icon);
+ if (item.icon != null) {
+ iv.setImageDrawable(item.icon);
+ } else {
+ iv.setImageResource(item.iconResId);
+ }
+ iv.getOverlay().clear();
+ if (item.overlay != null) {
+ item.overlay.setBounds(0, 0, mQsDetailIconOverlaySize, mQsDetailIconOverlaySize);
+ iv.getOverlay().add(item.overlay);
+ }
+ final TextView title = view.findViewById(android.R.id.title);
+ title.setText(item.line1);
+ final TextView summary = view.findViewById(android.R.id.summary);
+ final boolean twoLines = !TextUtils.isEmpty(item.line2);
+ title.setMaxLines(twoLines ? 1 : 2);
+ summary.setVisibility(twoLines ? VISIBLE : GONE);
+ summary.setText(twoLines ? item.line2 : null);
+ view.setOnClickListener(v -> {
+ if (mCallback != null) {
+ mCallback.onDetailItemClick(item);
+ }
+ });
+
+ final ImageView icon2 = view.findViewById(android.R.id.icon2);
+ if (item.canDisconnect) {
+ icon2.setImageResource(R.drawable.ic_qs_cancel);
+ icon2.setVisibility(VISIBLE);
+ icon2.setClickable(true);
+ icon2.setOnClickListener(v -> {
+ if (mCallback != null) {
+ mCallback.onDetailItemDisconnect(item);
+ }
+ });
+ } else if (item.icon2 != -1) {
+ icon2.setVisibility(VISIBLE);
+ icon2.setImageResource(item.icon2);
+ icon2.setClickable(false);
+ } else {
+ icon2.setVisibility(GONE);
+ }
+
+ return view;
+ }
+ };
+
+ private class H extends Handler {
+ private static final int SET_ITEMS = 1;
+ private static final int SET_CALLBACK = 2;
+ private static final int SET_ITEMS_VISIBLE = 3;
+
+ public H() {
+ super(Looper.getMainLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == SET_ITEMS) {
+ handleSetItems((Item[]) msg.obj);
+ } else if (msg.what == SET_CALLBACK) {
+ handleSetCallback((OutputChooserLayout.Callback) msg.obj);
+ } else if (msg.what == SET_ITEMS_VISIBLE) {
+ handleSetItemsVisible(msg.arg1 != 0);
+ }
+ }
+ }
+
+ public static class Item {
+ public int iconResId;
+ public Drawable icon;
+ public Drawable overlay;
+ public CharSequence line1;
+ public CharSequence line2;
+ public Object tag;
+ public boolean canDisconnect;
+ public int icon2 = -1;
+ }
+
+ public interface Callback {
+ void onDetailItemClick(Item item);
+ void onDetailItemDisconnect(Item item);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 4dff9bd..bc98140 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -134,6 +134,10 @@
mController.setVolumePolicy(mVolumePolicy);
}
+ void setEnableDialogs(boolean volumeUi, boolean safetyWarning) {
+ mController.setEnableDialogs(volumeUi, safetyWarning);
+ }
+
@Override
public void onUserActivity() {
final KeyguardViewMediator kvm = mSysui.getComponent(KeyguardViewMediator.class);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index b08b26d..2129790 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;
@@ -104,6 +103,8 @@
private final Vibrator mVibrator;
private final boolean mHasVibrator;
private boolean mShowA11yStream;
+ private boolean mShowVolumeDialog;
+ private boolean mShowSafetyWarning;
private boolean mDestroyed;
private VolumePolicy mVolumePolicy;
@@ -283,6 +284,11 @@
mWorker.obtainMessage(W.SET_ACTIVE_STREAM, stream, 0).sendToTarget();
}
+ public void setEnableDialogs(boolean volumeUi, boolean safetyWarning) {
+ mShowVolumeDialog = volumeUi;
+ mShowSafetyWarning = safetyWarning;
+ }
+
public void vibrate() {
if (mHasVibrator) {
mVibrator.vibrate(VIBRATE_HINT_DURATION);
@@ -312,7 +318,9 @@
}
private void onShowSafetyWarningW(int flags) {
- mCallbacks.onShowSafetyWarning(flags);
+ if (mShowSafetyWarning) {
+ mCallbacks.onShowSafetyWarning(flags);
+ }
}
private void onAccessibilityModeChanged(Boolean showA11yStream) {
@@ -344,7 +352,8 @@
&& mStatusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
&& mStatusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
&& mStatusBar.isDeviceInteractive()
- && (flags & AudioManager.FLAG_SHOW_UI) != 0;
+ && (flags & AudioManager.FLAG_SHOW_UI) != 0
+ && mShowVolumeDialog;
}
boolean onVolumeChangedW(int stream, int flags) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 0d41e20..d7c8010 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -19,6 +19,7 @@
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
+import static com.android.systemui.volume.Events.DISMISS_REASON_OUTPUT_CHOOSER;
import static com.android.systemui.volume.Events.DISMISS_REASON_TOUCH_OUTSIDE;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -29,12 +30,14 @@
import android.app.KeyguardManager;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
+import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.os.Debug;
@@ -43,6 +46,8 @@
import android.os.Message;
import android.os.SystemClock;
import android.provider.Settings.Global;
+import android.transition.AutoTransition;
+import android.transition.TransitionManager;
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -67,7 +72,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;
@@ -97,22 +101,27 @@
private final VolumeDialogController mController;
private Window mWindow;
- private HardwareUiLayout mHardwareLayout;
private CustomDialog mDialog;
private ViewGroup mDialogView;
private ViewGroup mDialogRowsView;
- private ViewGroup mDialogContentView;
+ private ImageButton mExpandButton;
+ private ImageButton mRingerIcon;
+ private ImageButton mOutputChooser;
+ private TextView mRingerStatus;
private final List<VolumeRow> mRows = new ArrayList<>();
private ConfigurableTexts mConfigurableTexts;
private final SparseBooleanArray mDynamic = new SparseBooleanArray();
private final KeyguardManager mKeyguard;
private final AccessibilityManager mAccessibilityMgr;
private final Object mSafetyWarningLock = new Object();
+ private final Object mOutputChooserLock = new Object();
private final Accessibility mAccessibility = new Accessibility();
private final ColorStateList mActiveSliderTint;
private final ColorStateList mInactiveSliderTint;
private boolean mShowing;
+ private boolean mExpanded;
+ private boolean mExpandButtonAnimationRunning;
private boolean mShowA11yStream;
private int mActiveStream;
@@ -121,6 +130,7 @@
private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE;
private State mState;
private SafetyWarningDialog mSafetyWarning;
+ private OutputChooserDialog mOutputChooserDialog;
private boolean mHovering = false;
public VolumeDialogImpl(Context context) {
@@ -160,54 +170,77 @@
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);
- mDialogView.setOnHoverListener(new View.OnHoverListener() {
- @Override
- public boolean onHover(View v, MotionEvent event) {
- int action = event.getActionMasked();
- mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
- || (action == MotionEvent.ACTION_HOVER_MOVE);
- rescheduleTimeoutH();
- return true;
- }
+ mDialog.setOnShowListener(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();
});
- mHardwareLayout = HardwareUiLayout.get(mDialogView);
- mHardwareLayout.setOutsideTouchListener(view -> dismiss(DISMISS_REASON_TOUCH_OUTSIDE));
+ mDialogView = mDialog.findViewById(R.id.volume_dialog);
+ mDialogView.setOnHoverListener((v, event) -> {
+ int action = event.getActionMasked();
+ mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
+ || (action == MotionEvent.ACTION_HOVER_MOVE);
+ rescheduleTimeoutH();
+ return true;
+ });
+ VolumeUiLayout hardwareLayout = VolumeUiLayout.get(mDialogView);
+ hardwareLayout.setOutsideTouchListener(view -> dismiss(DISMISS_REASON_TOUCH_OUTSIDE));
- mDialogContentView = mDialog.findViewById(R.id.volume_dialog_content);
- mDialogRowsView = mDialogContentView.findViewById(R.id.volume_dialog_rows);
+ ViewGroup dialogContentView = mDialog.findViewById(R.id.volume_dialog_content);
+ mDialogRowsView = dialogContentView.findViewById(R.id.volume_dialog_rows);
+ mRingerIcon = mDialog.findViewById(R.id.ringer_icon);
+ mRingerStatus = mDialog.findViewById(R.id.ringer_status);
+
+ mExpanded = false;
+ mExpandButton = mDialogView.findViewById(R.id.volume_expand_button);
+ mExpandButton.setOnClickListener(mClickExpand);
+ mExpandButton.setVisibility(
+ AudioSystem.isSingleVolume(mContext) ? View.GONE : View.VISIBLE);
+
+ mOutputChooser = mDialogView.findViewById(R.id.output_chooser);
+ mOutputChooser.setOnClickListener(mClickOutputChooser);
if (mRows.isEmpty()) {
addRow(AudioManager.STREAM_MUSIC,
- R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true);
+ R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true, 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, true, false);
addRow(AudioManager.STREAM_ALARM,
- R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, false);
+ R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, true, false);
addRow(AudioManager.STREAM_VOICE_CALL,
- R.drawable.ic_volume_voice, R.drawable.ic_volume_voice, false);
+ R.drawable.ic_volume_voice, R.drawable.ic_volume_voice, false, false);
addRow(AudioManager.STREAM_BLUETOOTH_SCO,
- R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false);
- addRow(AudioManager.STREAM_SYSTEM,
- R.drawable.ic_volume_system, R.drawable.ic_volume_system_mute, false);
+ R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false, false);
+ addRow(AudioManager.STREAM_SYSTEM, R.drawable.ic_volume_system,
+ R.drawable.ic_volume_system_mute, false, false);
addRow(AudioManager.STREAM_ACCESSIBILITY, R.drawable.ic_volume_accessibility,
- R.drawable.ic_volume_accessibility, true);
+ R.drawable.ic_volume_accessibility, true, false);
}
} else {
addExistingRows();
}
updateRowsH(getActiveRow());
+ initRingerH();
}
private ColorStateList loadColorStateList(int colorResId) {
@@ -230,14 +263,15 @@
mHandler.sendEmptyMessage(H.RECHECK_ALL);
}
- private void addRow(int stream, int iconRes, int iconMuteRes, boolean important) {
- addRow(stream, iconRes, iconMuteRes, important, false);
+ private void addRow(int stream, int iconRes, int iconMuteRes, boolean important,
+ boolean defaultStream) {
+ addRow(stream, iconRes, iconMuteRes, important, defaultStream, false);
}
private void addRow(int stream, int iconRes, int iconMuteRes, boolean important,
- boolean dynamic) {
+ boolean defaultStream, boolean dynamic) {
VolumeRow row = new VolumeRow();
- initRow(row, stream, iconRes, iconMuteRes, important);
+ initRow(row, stream, iconRes, iconMuteRes, important, defaultStream);
int rowSize;
int viewSize;
if (mShowA11yStream && dynamic && (rowSize = mRows.size()) > 1
@@ -255,7 +289,8 @@
int N = mRows.size();
for (int i = 0; i < N; i++) {
final VolumeRow row = mRows.get(i);
- initRow(row, row.stream, row.iconRes, row.iconMuteRes, row.important);
+ initRow(row, row.stream, row.iconRes, row.iconMuteRes, row.important,
+ row.defaultStream);
mDialogRowsView.addView(row.view);
updateVolumeRowH(row);
}
@@ -280,6 +315,7 @@
public void dump(PrintWriter writer) {
writer.println(VolumeDialogImpl.class.getSimpleName() + " state:");
writer.print(" mShowing: "); writer.println(mShowing);
+ writer.print(" mExpanded: "); writer.println(mExpanded);
writer.print(" mActiveStream: "); writer.println(mActiveStream);
writer.print(" mDynamic: "); writer.println(mDynamic);
writer.print(" mAutomute: "); writer.println(mAutomute);
@@ -298,11 +334,12 @@
@SuppressLint("InflateParams")
private void initRow(final VolumeRow row, final int stream, int iconRes, int iconMuteRes,
- boolean important) {
+ boolean important, boolean defaultStream) {
row.stream = stream;
row.iconRes = iconRes;
row.iconMuteRes = iconMuteRes;
row.important = important;
+ row.defaultStream = defaultStream;
row.view = mDialog.getLayoutInflater().inflate(R.layout.volume_dialog_row, null);
row.view.setId(row.stream);
row.view.setTag(row);
@@ -340,40 +377,61 @@
row.icon = row.view.findViewById(R.id.volume_row_icon);
row.icon.setImageResource(iconRes);
if (row.stream != AudioSystem.STREAM_ACCESSIBILITY) {
- row.icon.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Events.writeEvent(mContext, Events.EVENT_ICON_CLICK, row.stream, row.iconState);
- mController.setActiveStream(row.stream);
- if (row.stream == 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 = row.ss.level == 0;
- mController.setStreamVolume(stream,
- wasZero ? row.lastAudibleLevel : 0);
- }
+ row.icon.setOnClickListener(v -> {
+ Events.writeEvent(mContext, Events.EVENT_ICON_CLICK, row.stream, row.iconState);
+ mController.setActiveStream(row.stream);
+ if (row.stream == 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 {
- mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
- if (row.ss.level == 0) {
- mController.setStreamVolume(stream, 1);
- }
+ final boolean wasZero = row.ss.level == 0;
+ mController.setStreamVolume(stream,
+ wasZero ? row.lastAudibleLevel : 0);
}
} else {
- final boolean vmute = row.ss.level == row.ss.levelMin;
- mController.setStreamVolume(stream,
- vmute ? row.lastAudibleLevel : row.ss.levelMin);
+ mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
+ if (row.ss.level == 0) {
+ mController.setStreamVolume(stream, 1);
+ }
}
- row.userAttempt = 0; // reset the grace period, slider updates immediately
+ } else {
+ final boolean vmute = row.ss.level == row.ss.levelMin;
+ mController.setStreamVolume(stream,
+ vmute ? row.lastAudibleLevel : row.ss.levelMin);
}
+ row.userAttempt = 0; // reset the grace period, slider updates immediately
});
} else {
row.icon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
}
}
+ 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 +447,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();
@@ -422,8 +465,8 @@
private int computeTimeoutH() {
if (mAccessibility.mFeedbackEnabled) return 20000;
if (mHovering) return 16000;
+ if (mExpanded) return 5000;
if (mSafetyWarning != null) return 5000;
- if (mActiveStream == AudioManager.STREAM_MUSIC) return 1500;
return 3000;
}
@@ -431,16 +474,24 @@
mHandler.removeMessages(H.DISMISS);
mHandler.removeMessages(H.SHOW);
if (!mShowing) return;
+ mDialogView.animate().cancel();
mShowing = false;
- mHardwareLayout.setTranslationX(0);
- mHardwareLayout.setAlpha(1);
- mHardwareLayout.animate()
+
+ updateExpandedH(false /* expanding */, true /* dismissing */);
+
+ 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);
@@ -460,6 +511,76 @@
}
}
+ private void updateExpandedH(final boolean expanded, final boolean dismissing) {
+ if (D.BUG) Log.d(TAG, "updateExpandedH " + expanded);
+
+ if (mExpanded == expanded) return;
+ mExpanded = expanded;
+ mExpandButtonAnimationRunning = isAttached();
+ updateExpandButtonH();
+ TransitionManager.endTransitions(mDialogView);
+ final VolumeRow activeRow = getActiveRow();
+ if (!dismissing) {
+ mWindow.setLayout(mWindow.getAttributes().width, ViewGroup.LayoutParams.MATCH_PARENT);
+ TransitionManager.beginDelayedTransition(mDialogView, getTransition());
+ }
+ updateRowsH(activeRow);
+ rescheduleTimeoutH();
+ }
+
+ private AutoTransition getTransition() {
+ AutoTransition transition = new AutoTransition();
+ transition.setDuration(300);
+ transition.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+ return transition;
+ }
+
+ private void updateExpandButtonH() {
+ if (D.BUG) Log.d(TAG, "updateExpandButtonH");
+
+ mExpandButton.setClickable(!mExpandButtonAnimationRunning);
+ if (!(mExpandButtonAnimationRunning && isAttached())) {
+ final int res = mExpanded ? R.drawable.ic_volume_collapse_animation
+ : R.drawable.ic_volume_expand_animation;
+ if (hasTouchFeature()) {
+ mExpandButton.setImageResource(res);
+ } else {
+ // if there is no touch feature, show the volume ringer instead
+ mExpandButton.setImageResource(R.drawable.ic_volume_ringer);
+ mExpandButton.setBackgroundResource(0); // remove gray background emphasis
+ }
+ mExpandButton.setContentDescription(mContext.getString(mExpanded ?
+ R.string.accessibility_volume_collapse : R.string.accessibility_volume_expand));
+ }
+ if (mExpandButtonAnimationRunning) {
+ final Drawable d = mExpandButton.getDrawable();
+ if (d instanceof AnimatedVectorDrawable) {
+ // workaround to reset drawable
+ final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) d.getConstantState()
+ .newDrawable();
+ mExpandButton.setImageDrawable(avd);
+ avd.start();
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mExpandButtonAnimationRunning = false;
+ updateExpandButtonH();
+ rescheduleTimeoutH();
+ }
+ }, 300);
+ }
+ }
+ }
+
+ private boolean isAttached() {
+ return mDialogView != null && mDialogView.isAttachedToWindow();
+ }
+
+ private boolean hasTouchFeature() {
+ final PackageManager pm = mContext.getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
+ }
+
private boolean shouldBeVisibleH(VolumeRow row, VolumeRow activeRow) {
boolean isActive = row == activeRow;
if (row.stream == AudioSystem.STREAM_ACCESSIBILITY) {
@@ -473,7 +594,7 @@
return true;
}
- return row.important || isActive;
+ return row.defaultStream || isActive || (mExpanded && row.important);
}
private void updateRowsH(final VolumeRow activeRow) {
@@ -493,6 +614,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;
+ 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--) {
@@ -516,7 +684,7 @@
mDynamic.put(stream, true);
if (findRow(stream) == null) {
addRow(stream, R.drawable.ic_volume_remote, R.drawable.ic_volume_remote_mute, true,
- true);
+ false, true);
}
}
@@ -529,6 +697,7 @@
for (VolumeRow row : mRows) {
updateVolumeRowH(row);
}
+ updateRingerH();
}
private void updateVolumeRowH(VolumeRow row) {
@@ -750,6 +919,23 @@
rescheduleTimeoutH();
}
+ private void showOutputChooserH() {
+ synchronized (mOutputChooserLock) {
+ if (mOutputChooserDialog != null) {
+ return;
+ }
+ mOutputChooserDialog = new OutputChooserDialog(mContext) {
+ @Override
+ protected void cleanUp() {
+ synchronized (mOutputChooserLock) {
+ mOutputChooserDialog = null;
+ }
+ }
+ };
+ mOutputChooserDialog.show();
+ }
+ }
+
private String getStreamLabelH(StreamState ss) {
if (ss.remoteLabel != null) {
return ss.remoteLabel;
@@ -762,6 +948,25 @@
}
}
+ private final OnClickListener mClickExpand = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mExpandButton.animate().cancel();
+ final boolean newExpand = !mExpanded;
+ Events.writeEvent(mContext, Events.EVENT_EXPAND, newExpand);
+ updateExpandedH(newExpand, false /* dismissing */);
+ }
+ };
+
+ private final OnClickListener mClickOutputChooser = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // TODO: log
+ dismissH(DISMISS_REASON_OUTPUT_CHOOSER);
+ showOutputChooserH();
+ }
+ };
+
private final VolumeDialogController.Callbacks mControllerCallbackH
= new VolumeDialogController.Callbacks() {
@Override
@@ -817,8 +1022,7 @@
@Override
public void onAccessibilityModeChanged(Boolean showA11yStream) {
- boolean show = showA11yStream == null ? false : showA11yStream;
- mShowA11yStream = show;
+ mShowA11yStream = showA11yStream == null ? false : showA11yStream;
VolumeRow activeRow = getActiveRow();
if (!mShowA11yStream && AudioManager.STREAM_ACCESSIBILITY == activeRow.stream) {
dismissH(Events.DISMISS_STREAM_GONE);
@@ -1019,6 +1223,7 @@
private int iconRes;
private int iconMuteRes;
private boolean important;
+ private boolean defaultStream;
private ColorStateList cachedSliderTint;
private int iconState; // from Events
private ObjectAnimator anim; // slider progress animation for non-touch-related updates
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 02969e4..6f65b08 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -40,9 +40,13 @@
@Override
public void start() {
- mEnabled = mContext.getResources().getBoolean(R.bool.enable_volume_ui);
+ boolean enableVolumeUi = mContext.getResources().getBoolean(R.bool.enable_volume_ui);
+ boolean enableSafetyWarning =
+ mContext.getResources().getBoolean(R.bool.enable_safety_warning);
+ mEnabled = enableVolumeUi || enableSafetyWarning;
if (!mEnabled) return;
mVolumeComponent = new VolumeDialogComponent(this, mContext, null);
+ mVolumeComponent.setEnableDialogs(enableVolumeUi, enableSafetyWarning);
putComponent(VolumeComponent.class, getVolumeComponent());
setDefaultVolumeController();
}
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/Android.mk b/packages/SystemUI/tests/Android.mk
index b695919..9d44895 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -54,11 +54,15 @@
mockito-target-minus-junit4 \
SystemUI-proto \
SystemUI-tags \
- legacy-android-test \
testables \
truth-prebuilt \
-LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.car
+LOCAL_JAVA_LIBRARIES := \
+ android.test.runner \
+ telephony-common \
+ android.car \
+ android.test.base \
+
LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui:com.android.keyguard
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 1c104cf..3e6bd7e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
@@ -28,6 +28,7 @@
Callback callback;
boolean pulseExtended;
boolean animateWakeup;
+ boolean animateScreenOff;
boolean dozing;
float doubleTapX;
float doubleTapY;
@@ -103,6 +104,11 @@
}
@Override
+ public void setAnimateScreenOff(boolean animateScreenOff) {
+ this.animateScreenOff = animateScreenOff;
+ }
+
+ @Override
public void onDoubleTap(float x, float y) {
doubleTapX = y;
doubleTapY = y;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
index 19a30cc..75ade9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.doze;
+import static com.android.systemui.doze.DozeMachine.State.DOZE;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
import static com.android.systemui.doze.DozeMachine.State.INITIALIZED;
@@ -28,19 +29,20 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.AlarmManager;
-import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
-import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.wakelock.WakeLockFake;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -66,8 +68,11 @@
mWakeLock = new WakeLockFake();
mHost = new DozeHostFake();
mHandler = mHandlerThread.getThreadHandler();
+ DozeParameters params = mock(DozeParameters.class);
+ when(params.getCanControlScreenOffAnimation()).thenReturn(true);
+ when(params.getDisplayNeedsBlanking()).thenReturn(false);
- mDozeUi = new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler);
+ mDozeUi = new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler, params);
}
@After
@@ -89,4 +94,20 @@
verify(mAlarmManager).setExact(anyInt(), anyLong(), eq("doze_time_tick"), any(), any());
}
+
+ @Test
+ public void propagatesAnimateScreenOff() {
+ Assert.assertTrue("animateScreenOff should be true", mHost.animateScreenOff);
+
+ DozeParameters params = mock(DozeParameters.class);
+ new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler, params);
+ Assert.assertFalse("animateScreenOff should be false", mHost.animateScreenOff);
+ }
+
+ @Test
+ public void transitionSetsAnimateWakeup() {
+ mHost.animateWakeup = false;
+ mDozeUi.transitionTo(UNINITIALIZED, DOZE);
+ Assert.assertTrue("animateScreenOff should be true", mHost.animateWakeup);
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
index 58ff46a..544585a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
@@ -50,7 +50,7 @@
@Test
public void testGroupSummaryNotShowingIconWhenPublic() {
mGroup.setSensitive(true, true);
- mGroup.setHideSensitive(true, false, 0, 0);
+ mGroup.setHideSensitiveForIntrinsicHeight(true);
Assert.assertTrue(mGroup.isSummaryWithChildren());
Assert.assertFalse(mGroup.isShowingIcon());
}
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..f562340
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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;
+ private NotificationRemoteInputManager mRemoteInputManager;
+
+ @Before
+ public void setUp() {
+ mHandler = new Handler(Looper.getMainLooper());
+ mPresenter = mock(NotificationPresenter.class);
+ mNotificationData = mock(NotificationData.class);
+ mRanking = mock(NotificationListenerService.RankingMap.class);
+ mRemoteInputManager = mock(NotificationRemoteInputManager.class);
+ mKeysKeptForRemoteInput = new HashSet<>();
+
+ when(mPresenter.getHandler()).thenReturn(mHandler);
+ when(mPresenter.getNotificationData()).thenReturn(mNotificationData);
+ when(mRemoteInputManager.getKeysKeptForRemoteInput()).thenReturn(mKeysKeptForRemoteInput);
+
+ mListener = new NotificationListener(mPresenter, mRemoteInputManager, 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/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
new file mode 100644
index 0000000..b881c09
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -0,0 +1,118 @@
+package com.android.systemui.statusbar;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.content.Context;
+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 com.google.android.collect.Sets;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationRemoteInputManagerTest extends SysuiTestCase {
+ private static final String TEST_PACKAGE_NAME = "test";
+ private static final int TEST_UID = 0;
+
+ private Handler mHandler;
+ private TestableNotificationRemoteInputManager mRemoteInputManager;
+ private StatusBarNotification mSbn;
+ private NotificationData.Entry mEntry;
+
+ @Mock private NotificationPresenter mPresenter;
+ @Mock private RemoteInputController.Delegate mDelegate;
+ @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
+ @Mock private NotificationRemoteInputManager.Callback mCallback;
+ @Mock private RemoteInputController mController;
+ @Mock private NotificationListenerService.RankingMap mRanking;
+ @Mock private ExpandableNotificationRow mRow;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mHandler = new Handler(Looper.getMainLooper());
+
+ when(mPresenter.getHandler()).thenReturn(mHandler);
+ when(mPresenter.getLatestRankingMap()).thenReturn(mRanking);
+
+ mRemoteInputManager = new TestableNotificationRemoteInputManager(mLockscreenUserManager,
+ mContext);
+ mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
+ 0, new Notification(), UserHandle.CURRENT, null, 0);
+ mEntry = new NotificationData.Entry(mSbn);
+ mEntry.row = mRow;
+
+ mRemoteInputManager.setUpWithPresenterForTest(mPresenter, mCallback, mDelegate,
+ mController);
+ }
+
+ @Test
+ public void testOnRemoveNotificationNotKept() {
+ assertFalse(mRemoteInputManager.onRemoveNotification(mEntry));
+ assertTrue(mRemoteInputManager.getRemoteInputEntriesToRemoveOnCollapse().isEmpty());
+ }
+
+ @Test
+ public void testOnRemoveNotificationKept() {
+ when(mController.isRemoteInputActive(mEntry)).thenReturn(true);
+ assertTrue(mRemoteInputManager.onRemoveNotification(mEntry));
+ assertTrue(mRemoteInputManager.getRemoteInputEntriesToRemoveOnCollapse().equals(
+ Sets.newArraySet(mEntry)));
+ }
+
+ @Test
+ public void testPerformOnRemoveNotification() {
+ when(mController.isRemoteInputActive(mEntry)).thenReturn(true);
+ mRemoteInputManager.getKeysKeptForRemoteInput().add(mEntry.key);
+ mRemoteInputManager.onPerformRemoveNotification(mSbn, mEntry);
+
+ verify(mController).removeRemoteInput(mEntry, null);
+ assertTrue(mRemoteInputManager.getKeysKeptForRemoteInput().isEmpty());
+ }
+
+ @Test
+ public void testRemoveRemoteInputEntriesKeptUntilCollapsed() {
+ mRemoteInputManager.getRemoteInputEntriesToRemoveOnCollapse().add(mEntry);
+ mRemoteInputManager.removeRemoteInputEntriesKeptUntilCollapsed();
+
+ assertTrue(mRemoteInputManager.getRemoteInputEntriesToRemoveOnCollapse().isEmpty());
+ verify(mController).removeRemoteInput(mEntry, null);
+ verify(mPresenter).removeNotification(mEntry.key, mRanking);
+ }
+
+ private class TestableNotificationRemoteInputManager extends NotificationRemoteInputManager {
+
+ public TestableNotificationRemoteInputManager(
+ NotificationLockscreenUserManager lockscreenUserManager, Context context) {
+ super(lockscreenUserManager, context);
+ }
+
+ public void setUpWithPresenterForTest(NotificationPresenter presenter,
+ Callback callback,
+ RemoteInputController.Delegate delegate,
+ RemoteInputController controller) {
+ super.setUpWithPresenter(presenter, callback, delegate);
+ mRemoteInputController = controller;
+ }
+ }
+}
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/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index b9f695b..a40ef64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -70,6 +70,7 @@
mScrimVisibilityCallback = (Boolean visible) -> mScrimVisibile = visible;
mDozeParamenters = mock(DozeParameters.class);
when(mDozeParamenters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled);
+ when(mDozeParamenters.getDisplayNeedsBlanking()).thenReturn(true);
mScrimController = new SynchronousScrimController(mLightBarController, mScrimBehind,
mScrimInFront, mHeadsUpScrim, mScrimVisibilityCallback, mDozeParamenters);
}
@@ -229,6 +230,15 @@
verify(mWakeLock, times(1)).release();
}
+ @Test
+ public void testCallbackInvokedOnSameStateTransition() {
+ mScrimController.transitionTo(ScrimState.UNLOCKED);
+ mScrimController.finishAnimationsImmediately();
+ ScrimController.Callback callback = mock(ScrimController.Callback.class);
+ mScrimController.transitionTo(ScrimState.UNLOCKED, callback);
+ verify(callback, times(1)).onFinished();
+ }
+
private void assertScrimTint(ScrimView scrimView, boolean tinted) {
final boolean viewIsTinted = scrimView.getTint() != Color.TRANSPARENT;
final String name = scrimView == mScrimInFront ? "front" : "back";
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..e4c33f1 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
@@ -26,6 +26,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -54,6 +55,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 +73,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,8 +105,10 @@
PowerManager mPowerManager;
SystemServicesProxy mSystemServicesProxy;
NotificationPanelView mNotificationPanelView;
+ ScrimController mScrimController;
IStatusBarService mBarService;
ArrayList<Entry> mNotificationList;
+ FingerprintUnlockController mFingerprintUnlockController;
private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
@Before
@@ -129,6 +134,8 @@
mNotificationPanelView = mock(NotificationPanelView.class);
when(mNotificationPanelView.getLayoutParams()).thenReturn(new LayoutParams(0, 0));
mNotificationList = mock(ArrayList.class);
+ mScrimController = mock(ScrimController.class);
+ mFingerprintUnlockController = mock(FingerprintUnlockController.class);
IPowerManager powerManagerService = mock(IPowerManager.class);
HandlerThread handlerThread = new HandlerThread("TestThread");
handlerThread.start();
@@ -141,7 +148,7 @@
mStatusBar = new TestableStatusBar(mStatusBarKeyguardViewManager, mUnlockMethodCache,
mKeyguardIndicationController, mStackScroller, mHeadsUpManager,
mNotificationData, mPowerManager, mSystemServicesProxy, mNotificationPanelView,
- mBarService);
+ mBarService, mScrimController, mFingerprintUnlockController);
mStatusBar.mContext = mContext;
mStatusBar.mComponents = mContext.getComponents();
doAnswer(invocation -> {
@@ -426,6 +433,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 +451,7 @@
try {
mStatusBar.handleVisibleToUserChanged(true);
-
+ waitForUiOffloadThread();
verify(mBarService, never()).onPanelHidden();
verify(mBarService, times(1)).onPanelRevealed(false, 1);
} catch (RemoteException e) {
@@ -462,7 +470,7 @@
try {
mStatusBar.handleVisibleToUserChanged(true);
-
+ waitForUiOffloadThread();
verify(mBarService, never()).onPanelHidden();
verify(mBarService, times(1)).onPanelRevealed(true, 5);
} catch (RemoteException e) {
@@ -481,7 +489,7 @@
try {
mStatusBar.handleVisibleToUserChanged(true);
-
+ waitForUiOffloadThread();
verify(mBarService, never()).onPanelHidden();
verify(mBarService, times(1)).onPanelRevealed(false, 5);
} catch (RemoteException e) {
@@ -524,15 +532,36 @@
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.mDozeScrimController = mock(DozeScrimController.class);
+ mStatusBar.notifyFpAuthModeChanged();
+ verify(mScrimController).transitionTo(any(), any());
+ }
+
+ @Test
+ public void testFingerprintUnlock_UpdatesScrims() {
+ // Simulate unlocking from AoD with fingerprint.
+ when(mFingerprintUnlockController.getMode())
+ .thenReturn(FingerprintUnlockController.MODE_WAKE_AND_UNLOCK);
+ mStatusBar.updateScrimController();
+ verify(mScrimController).transitionTo(eq(ScrimState.UNLOCKED), 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,
+ FingerprintUnlockController fingerprintUnlockController) {
mStatusBarKeyguardViewManager = man;
mUnlockMethodCache = unlock;
mKeyguardIndicationController = key;
@@ -545,7 +574,8 @@
mNotificationPanel = panelView;
mBarService = barService;
mWakefulnessLifecycle = createAwakeWakefulnessLifecycle();
- mScrimController = mock(ScrimController.class);
+ mScrimController = scrimController;
+ mFingerprintUnlockController = fingerprintUnlockController;
}
private WakefulnessLifecycle createAwakeWakefulnessLifecycle() {
@@ -568,4 +598,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/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
index 06568f7..401fd68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -45,6 +45,7 @@
mCallback = mock(VolumeDialogControllerImpl.C.class);
mStatusBar = mock(StatusBar.class);
mVolumeController = new TestableVolumeDialogControllerImpl(mContext, mCallback, mStatusBar);
+ mVolumeController.setEnableDialogs(true, true);
}
@Test
diff --git a/packages/VpnDialogs/res/values-bs/strings.xml b/packages/VpnDialogs/res/values-bs/strings.xml
index 1862bb7..56812d5 100644
--- a/packages/VpnDialogs/res/values-bs/strings.xml
+++ b/packages/VpnDialogs/res/values-bs/strings.xml
@@ -24,7 +24,7 @@
<string name="data_transmitted" msgid="7988167672982199061">"Poslano:"</string>
<string name="data_received" msgid="4062776929376067820">"Primljeno:"</string>
<string name="data_value_format" msgid="2192466557826897580">"Broj bajtova: <xliff:g id="NUMBER_0">%1$s</xliff:g>/Broj paketa: <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="always_on_disconnected_title" msgid="1906740176262776166">"Ne može se povezati na stalno uključen VPN"</string>
+ <string name="always_on_disconnected_title" msgid="1906740176262776166">"Nije se moguće povezati na stalno uključen VPN"</string>
<string name="always_on_disconnected_message" msgid="555634519845992917">"Aplikacija <xliff:g id="VPN_APP_0">%1$s</xliff:g> je postavljena da ostane povezana sve vrijeme, ali se trenutno ne može povezati. Telefon će koristiti javnu mrežu dok se ponovo ne mogne povezati s aplikacijom <xliff:g id="VPN_APP_1">%1$s</xliff:g>."</string>
<string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"Aplikacija <xliff:g id="VPN_APP">%1$s</xliff:g> je postavljena da ostane povezana sve vrijeme, ali se trenutno ne može povezati. Nećete biti imati vezu dok se VPN ne mogne ponovo povezati."</string>
<string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
diff --git a/packages/WAPPushManager/tests/Android.mk b/packages/WAPPushManager/tests/Android.mk
index 1dea798..bfc85ab 100644
--- a/packages/WAPPushManager/tests/Android.mk
+++ b/packages/WAPPushManager/tests/Android.mk
@@ -18,8 +18,8 @@
# We only want this apk build for tests.
LOCAL_MODULE_TAGS := tests
-LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
-LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
+LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.test.base
+LOCAL_STATIC_JAVA_LIBRARIES := junit
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 32af29d..935b787 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3953,6 +3953,10 @@
// An autofill session was started
// Package: Package of app that is autofilled
+ // NOTE: starting on OS MR1, it also added the following field:
+ // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+ // NOTE: starting on OS P, it also added the following field:
+ // Tag FIELD_FLAGS - Flags used to start the session
AUTOFILL_SESSION_STARTED = 906;
// An autofill request was processed by a service
@@ -3960,7 +3964,11 @@
// Type TYPE_FAILURE: The request failed
// Package: Package of app that is autofilled
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
- // Tag FIELD_AUTOFILL_NUM_DATASET: The number of datasets returned (only in success case)
+ // Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets returned (only in success case)
+ // NOTE: starting on OS P, it also added:
+ // Type TYPE_CLOSE: Service returned a null response.
+ // Tag FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS: if service requested field classification,
+ // number of entries field ids in the request.
AUTOFILL_REQUEST = 907;
// Tag of a field for a package of an autofill service
@@ -4138,6 +4146,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
@@ -4850,7 +4871,6 @@
// Counter: duration (in ms) that autofill will be disabled
// OS: P
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
- // Tag FIELD_CLASS_NAME: Name of the Package of service that processed the request
AUTOFILL_SERVICE_DISABLED_APP = 1231;
// An autofill service asked to disable autofill for a given activity.
@@ -5013,8 +5033,68 @@
// 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;
+
+ // Tag of a field for the number of ids in an autofill field classification request.
+ FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS = 1271;
+
+ // An autofill service updated its user data
+ // Package: Package of the autofill service that updated the user data
+ // Counter: number of fields added (or 0 if reset)
+ // OS: P
+ AUTOFILL_USERDATA_UPDATED = 1272;
+
+ // Some data entered by the user matched the field classification requested by the service.
+ // Package: Package of app that is autofilled
+ // Counter: number of matches found
+ // OS: P
+ // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+ // Tag FIELD_AUTOFILL_MATCH_SCORE: Average score of the matches, in the range of 0 to 100
+ AUTOFILL_FIELD_CLASSIFICATION_MATCHES = 1273;
+
+ // Tag used to report autofill field classification scores
+ FIELD_AUTOFILL_MATCH_SCORE = 1274;
+
+ // ---- 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..d817da5 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -187,6 +187,12 @@
// to a Wi-Fi network
NOTE_WIFI_WRONG_PASSWORD = 42;
+ // Inform the user that Wifi Wake will re-enable wifi when possible
+ NOTE_WIFI_WAKE_ONBOARD = 43;
+
+ // Inform the user that Wifi Wake has automatically re-enabled Wifi
+ NOTE_WIFI_WAKE_TURNED_BACK_ON = 44;
+
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release
@@ -223,6 +229,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/sax/tests/saxtests/Android.mk b/sax/tests/saxtests/Android.mk
index d3fbd05..e0e490c 100644
--- a/sax/tests/saxtests/Android.mk
+++ b/sax/tests/saxtests/Android.mk
@@ -7,8 +7,8 @@
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-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
LOCAL_PACKAGE_NAME := FrameworksSaxTests
include $(BUILD_PACKAGE)
diff --git a/services/Android.bp b/services/Android.bp
new file mode 100644
index 0000000..d125adc
--- /dev/null
+++ b/services/Android.bp
@@ -0,0 +1,51 @@
+// merge all required services into one jar
+// ============================================================
+java_library {
+ name: "services",
+
+ dex_preopt: {
+ app_image: true,
+ profile: "art-profile",
+ },
+
+ srcs: [
+ "java/**/*.java",
+ ],
+
+ // The convention is to name each service module 'services.$(module_name)'
+ static_libs: [
+ "services.core",
+ "services.accessibility",
+ "services.appwidget",
+ "services.autofill",
+ "services.backup",
+ "services.companion",
+ "services.coverage",
+ "services.devicepolicy",
+ "services.midi",
+ "services.net",
+ "services.print",
+ "services.restrictions",
+ "services.usage",
+ "services.usb",
+ "services.voiceinteraction",
+ "android.hidl.base-V1.0-java",
+ ],
+
+ libs: [
+ "android.hidl.manager-V1.0-java",
+ ],
+
+ // Uncomment to enable output of certain warnings (deprecated, unchecked)
+ //javacflags: ["-Xlint"],
+
+}
+
+// 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
deleted file mode 100644
index ed2ba1f..0000000
--- a/services/Android.mk
+++ /dev/null
@@ -1,84 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# merge all required services into one jar
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services
-LOCAL_DEX_PREOPT_APP_IMAGE := true
-LOCAL_DEX_PREOPT_GENERATE_PROFILE := true
-LOCAL_DEX_PREOPT_PROFILE_CLASS_LISTING := $(LOCAL_PATH)/art-profile
-
-LOCAL_SRC_FILES := $(call all-java-files-under,java)
-
-# EventLogTags files.
-LOCAL_SRC_FILES += \
- core/java/com/android/server/EventLogTags.logtags
-
-# Uncomment to enable output of certain warnings (deprecated, unchecked)
-# LOCAL_JAVACFLAGS := -Xlint
-
-# Services that will be built as part of services.jar
-# These should map to directory names relative to this
-# Android.mk.
-services := \
- core \
- accessibility \
- appwidget \
- autofill \
- backup \
- companion \
- coverage\
- devicepolicy \
- midi \
- net \
- print \
- restrictions \
- usage \
- usb \
- voiceinteraction
-
-# The convention is to name each service module 'services.$(module_name)'
-LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services)) \
- android.hidl.base-V1.0-java \
- android.hardware.biometrics.fingerprint-V2.1-java
-
-LOCAL_JAVA_LIBRARIES := \
- android.hidl.manager-V1.0-java
-
-ifeq ($(EMMA_INSTRUMENT_FRAMEWORK),true)
-LOCAL_EMMA_INSTRUMENT := true
-endif
-
-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))
-# A full make is happening, so make everything.
-include $(call all-makefiles-under,$(LOCAL_PATH))
-else
-# If we ran an mm[m] command, we still want to build the individual
-# services that we depend on. This differs from the above condition
-# by only including service makefiles and not any tests or other
-# modules.
-include $(patsubst %,$(LOCAL_PATH)/%/Android.mk,$(services))
-endif
-
diff --git a/services/accessibility/Android.bp b/services/accessibility/Android.bp
new file mode 100644
index 0000000..f991d7b
--- /dev/null
+++ b/services/accessibility/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+ name: "services.accessibility",
+ srcs: ["java/**/*.java"],
+ libs: ["services.core"],
+}
diff --git a/services/accessibility/Android.mk b/services/accessibility/Android.mk
deleted file mode 100644
index ce89aa7..0000000
--- a/services/accessibility/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services.accessibility
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,java)
-
-LOCAL_JAVA_LIBRARIES := services.core
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java
index 7e94d7b..01679dd 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java
@@ -20,9 +20,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
-import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
-import android.accessibilityservice.GestureDescription;
import android.accessibilityservice.IAccessibilityServiceClient;
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.annotation.NonNull;
@@ -49,7 +47,6 @@
import android.view.View;
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.accessibility.IAccessibilityInteractionConnection;
@@ -58,6 +55,7 @@
import com.android.internal.os.SomeArgs;
import com.android.internal.util.DumpUtils;
+import com.android.server.accessibility.AccessibilityManagerService.RemoteAccessibilityConnection;
import com.android.server.accessibility.AccessibilityManagerService.SecurityPolicy;
import com.android.server.wm.WindowManagerInternal;
@@ -171,13 +169,13 @@
@NonNull MagnificationController getMagnificationController();
/**
- * Resolve a connection for a window id
+ * Resolve a connection wrapper for a window id
*
* @param windowId The id of the window of interest
*
* @return a connection to the window
*/
- IAccessibilityInteractionConnection getConnectionLocked(int windowId);
+ RemoteAccessibilityConnection getConnectionLocked(int windowId);
/**
* Perform the specified accessibility action
@@ -416,28 +414,28 @@
}
@Override
- public boolean findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
+ public String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
long accessibilityNodeId, String viewIdResName, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
final int resolvedWindowId;
- IAccessibilityInteractionConnection connection = null;
+ RemoteAccessibilityConnection connection;
Region partialInteractiveRegion = Region.obtain();
MagnificationSpec spec;
synchronized (mLock) {
mUsesAccessibilityCache = true;
if (!isCalledForCurrentUserLocked()) {
- return false;
+ return null;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
if (!permissionGranted) {
- return false;
+ return null;
} else {
connection = mSystemSupport.getConnectionLocked(resolvedWindowId);
if (connection == null) {
- return false;
+ return null;
}
}
if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
@@ -450,12 +448,14 @@
final int interrogatingPid = Binder.getCallingPid();
callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
interrogatingPid, interrogatingTid);
+ final int callingUid = Binder.getCallingUid();
final long identityToken = Binder.clearCallingIdentity();
try {
- connection.findAccessibilityNodeInfosByViewId(accessibilityNodeId, viewIdResName,
- partialInteractiveRegion, interactionId, callback, mFetchFlags,
+ connection.getRemote().findAccessibilityNodeInfosByViewId(accessibilityNodeId,
+ viewIdResName, partialInteractiveRegion, interactionId, callback, mFetchFlags,
interrogatingPid, interrogatingTid, spec);
- return true;
+ return mSecurityPolicy.computeValidReportedPackages(callingUid,
+ connection.getPackageName(), connection.getUid());
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
@@ -463,36 +463,36 @@
} finally {
Binder.restoreCallingIdentity(identityToken);
// Recycle if passed to another process.
- if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+ if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
partialInteractiveRegion.recycle();
}
}
- return false;
+ return null;
}
@Override
- public boolean findAccessibilityNodeInfosByText(int accessibilityWindowId,
+ public String[] findAccessibilityNodeInfosByText(int accessibilityWindowId,
long accessibilityNodeId, String text, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
final int resolvedWindowId;
- IAccessibilityInteractionConnection connection = null;
+ RemoteAccessibilityConnection connection;
Region partialInteractiveRegion = Region.obtain();
MagnificationSpec spec;
synchronized (mLock) {
mUsesAccessibilityCache = true;
if (!isCalledForCurrentUserLocked()) {
- return false;
+ return null;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
if (!permissionGranted) {
- return false;
+ return null;
} else {
connection = mSystemSupport.getConnectionLocked(resolvedWindowId);
if (connection == null) {
- return false;
+ return null;
}
}
if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
@@ -505,12 +505,14 @@
final int interrogatingPid = Binder.getCallingPid();
callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
interrogatingPid, interrogatingTid);
+ final int callingUid = Binder.getCallingUid();
final long identityToken = Binder.clearCallingIdentity();
try {
- connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
- partialInteractiveRegion, interactionId, callback, mFetchFlags,
+ connection.getRemote().findAccessibilityNodeInfosByText(accessibilityNodeId,
+ text, partialInteractiveRegion, interactionId, callback, mFetchFlags,
interrogatingPid, interrogatingTid, spec);
- return true;
+ return mSecurityPolicy.computeValidReportedPackages(callingUid,
+ connection.getPackageName(), connection.getUid());
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
@@ -518,36 +520,36 @@
} finally {
Binder.restoreCallingIdentity(identityToken);
// Recycle if passed to another process.
- if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+ if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
partialInteractiveRegion.recycle();
}
}
- return false;
+ return null;
}
@Override
- public boolean findAccessibilityNodeInfoByAccessibilityId(
+ public String[] findAccessibilityNodeInfoByAccessibilityId(
int accessibilityWindowId, long accessibilityNodeId, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags,
long interrogatingTid, Bundle arguments) throws RemoteException {
final int resolvedWindowId;
- IAccessibilityInteractionConnection connection = null;
+ RemoteAccessibilityConnection connection;
Region partialInteractiveRegion = Region.obtain();
MagnificationSpec spec;
synchronized (mLock) {
mUsesAccessibilityCache = true;
if (!isCalledForCurrentUserLocked()) {
- return false;
+ return null;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
if (!permissionGranted) {
- return false;
+ return null;
} else {
connection = mSystemSupport.getConnectionLocked(resolvedWindowId);
if (connection == null) {
- return false;
+ return null;
}
}
if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
@@ -560,12 +562,14 @@
final int interrogatingPid = Binder.getCallingPid();
callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
interrogatingPid, interrogatingTid);
+ final int callingUid = Binder.getCallingUid();
final long identityToken = Binder.clearCallingIdentity();
try {
- connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
- partialInteractiveRegion, interactionId, callback, mFetchFlags | flags,
- interrogatingPid, interrogatingTid, spec, arguments);
- return true;
+ connection.getRemote().findAccessibilityNodeInfoByAccessibilityId(
+ accessibilityNodeId, partialInteractiveRegion, interactionId, callback,
+ mFetchFlags | flags, interrogatingPid, interrogatingTid, spec, arguments);
+ return mSecurityPolicy.computeValidReportedPackages(callingUid,
+ connection.getPackageName(), connection.getUid());
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
@@ -573,36 +577,36 @@
} finally {
Binder.restoreCallingIdentity(identityToken);
// Recycle if passed to another process.
- if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+ if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
partialInteractiveRegion.recycle();
}
}
- return false;
+ return null;
}
@Override
- public boolean findFocus(int accessibilityWindowId, long accessibilityNodeId,
+ public String[] findFocus(int accessibilityWindowId, long accessibilityNodeId,
int focusType, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
final int resolvedWindowId;
- IAccessibilityInteractionConnection connection = null;
+ RemoteAccessibilityConnection connection;
Region partialInteractiveRegion = Region.obtain();
MagnificationSpec spec;
synchronized (mLock) {
if (!isCalledForCurrentUserLocked()) {
- return false;
+ return null;
}
resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
accessibilityWindowId, focusType);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
if (!permissionGranted) {
- return false;
+ return null;
} else {
connection = mSystemSupport.getConnectionLocked(resolvedWindowId);
if (connection == null) {
- return false;
+ return null;
}
}
if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
@@ -615,12 +619,14 @@
final int interrogatingPid = Binder.getCallingPid();
callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
interrogatingPid, interrogatingTid);
+ final int callingUid = Binder.getCallingUid();
final long identityToken = Binder.clearCallingIdentity();
try {
- connection.findFocus(accessibilityNodeId, focusType, partialInteractiveRegion,
- interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
- spec);
- return true;
+ connection.getRemote().findFocus(accessibilityNodeId, focusType,
+ partialInteractiveRegion, interactionId, callback, mFetchFlags,
+ interrogatingPid, interrogatingTid, spec);
+ return mSecurityPolicy.computeValidReportedPackages(callingUid,
+ connection.getPackageName(), connection.getUid());
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling findFocus()");
@@ -628,35 +634,35 @@
} finally {
Binder.restoreCallingIdentity(identityToken);
// Recycle if passed to another process.
- if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+ if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
partialInteractiveRegion.recycle();
}
}
- return false;
+ return null;
}
@Override
- public boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId,
+ public String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId,
int direction, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
final int resolvedWindowId;
- IAccessibilityInteractionConnection connection = null;
+ RemoteAccessibilityConnection connection;
Region partialInteractiveRegion = Region.obtain();
MagnificationSpec spec;
synchronized (mLock) {
if (!isCalledForCurrentUserLocked()) {
- return false;
+ return null;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
if (!permissionGranted) {
- return false;
+ return null;
} else {
connection = mSystemSupport.getConnectionLocked(resolvedWindowId);
if (connection == null) {
- return false;
+ return null;
}
}
if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
@@ -669,12 +675,14 @@
final int interrogatingPid = Binder.getCallingPid();
callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
interrogatingPid, interrogatingTid);
+ final int callingUid = Binder.getCallingUid();
final long identityToken = Binder.clearCallingIdentity();
try {
- connection.focusSearch(accessibilityNodeId, direction, partialInteractiveRegion,
- interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
- spec);
- return true;
+ connection.getRemote().focusSearch(accessibilityNodeId, direction,
+ partialInteractiveRegion, interactionId, callback, mFetchFlags,
+ interrogatingPid, interrogatingTid, spec);
+ return mSecurityPolicy.computeValidReportedPackages(callingUid,
+ connection.getPackageName(), connection.getUid());
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()");
@@ -682,11 +690,11 @@
} finally {
Binder.restoreCallingIdentity(identityToken);
// Recycle if passed to another process.
- if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+ if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
partialInteractiveRegion.recycle();
}
}
- return false;
+ return null;
}
@Override
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 3554448..ac0cdd7 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -24,12 +24,12 @@
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceClient;
-import android.accessibilityservice.IAccessibilityServiceConnection;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
import android.app.AlertDialog;
import android.app.PendingIntent;
+import android.appwidget.AppWidgetManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -72,6 +72,7 @@
import android.provider.SettingsStringUtil.SettingStringHelper;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
+import android.util.ArraySet;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -97,12 +98,15 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.ArrayUtils;
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 libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileDescriptor;
@@ -185,6 +189,8 @@
private final WindowManagerInternal mWindowManagerService;
+ private AppWidgetManagerInternal mAppWidgetService;
+
private final SecurityPolicy mSecurityPolicy;
private final MainHandler mMainHandler;
@@ -217,10 +223,10 @@
private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
new RemoteCallbackList<>();
- private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections =
+ private final SparseArray<RemoteAccessibilityConnection> mGlobalInteractionConnections =
new SparseArray<>();
- private AccessibilityConnectionWrapper mPictureInPictureActionReplacingConnection;
+ private RemoteAccessibilityConnection mPictureInPictureActionReplacingConnection;
private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<>();
@@ -452,6 +458,7 @@
// performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
+
// If the client is from a process that runs across users such as
// the system UI or the system we add it to the global state that
// is shared across users.
@@ -496,9 +503,14 @@
// We treat calls from a profile as if made by its parent as profiles
// share the accessibility state of the parent. The call below
- // performs the current profile parent resolution..
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
+
+ // Make sure the reported package is one the caller has access to.
+ event.setPackageName(mSecurityPolicy.resolveValidReportedPackageLocked(
+ event.getPackageName(), UserHandle.getCallingAppId(), resolvedUserId));
+
// This method does nothing for a background user.
if (resolvedUserId == mCurrentUserId) {
if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) {
@@ -616,30 +628,38 @@
@Override
public int addAccessibilityInteractionConnection(IWindow windowToken,
- IAccessibilityInteractionConnection connection, int userId) throws RemoteException {
+ IAccessibilityInteractionConnection connection, String packageName,
+ int userId) throws RemoteException {
synchronized (mLock) {
// We treat calls from a profile as if made by its parent as profiles
// share the accessibility state of the parent. The call below
// performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
+ final int resolvedUid = UserHandle.getUid(resolvedUserId, UserHandle.getCallingAppId());
+
+ // Make sure the reported package is one the caller has access to.
+ packageName = mSecurityPolicy.resolveValidReportedPackageLocked(
+ packageName, UserHandle.getCallingAppId(), resolvedUserId);
+
final int windowId = sNextWindowId++;
// If the window is from a process that runs across users such as
// the system UI or the system we add it to the global state that
// is shared across users.
if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
- AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
- windowId, connection, UserHandle.USER_ALL);
+ RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
+ windowId, connection, packageName, resolvedUid, UserHandle.USER_ALL);
wrapper.linkToDeath();
mGlobalInteractionConnections.put(windowId, wrapper);
mGlobalWindowTokens.put(windowId, windowToken.asBinder());
if (DEBUG) {
Slog.i(LOG_TAG, "Added global connection for pid:" + Binder.getCallingPid()
- + " with windowId: " + windowId + " and token: " + windowToken.asBinder());
+ + " with windowId: " + windowId + " and token: "
+ + windowToken.asBinder());
}
} else {
- AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
- windowId, connection, resolvedUserId);
+ RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
+ windowId, connection, packageName, resolvedUid, resolvedUserId);
wrapper.linkToDeath();
UserState userState = getUserStateLocked(resolvedUserId);
userState.mInteractionConnections.put(windowId, wrapper);
@@ -692,13 +712,13 @@
private int removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken,
SparseArray<IBinder> windowTokens,
- SparseArray<AccessibilityConnectionWrapper> interactionConnections) {
+ SparseArray<RemoteAccessibilityConnection> interactionConnections) {
final int count = windowTokens.size();
for (int i = 0; i < count; i++) {
if (windowTokens.valueAt(i) == windowToken) {
final int windowId = windowTokens.keyAt(i);
windowTokens.removeAt(i);
- AccessibilityConnectionWrapper wrapper = interactionConnections.get(windowId);
+ RemoteAccessibilityConnection wrapper = interactionConnections.get(windowId);
wrapper.unlinkToDeath();
interactionConnections.remove(windowId);
return windowId;
@@ -718,9 +738,9 @@
mPictureInPictureActionReplacingConnection = null;
}
if (connection != null) {
- AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
+ RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID,
- connection, UserHandle.USER_ALL);
+ connection, "foo.bar.baz", Process.SYSTEM_UID, UserHandle.USER_ALL);
mPictureInPictureActionReplacingConnection = wrapper;
wrapper.linkToDeath();
}
@@ -1897,8 +1917,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 +1932,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 +2141,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) {
@@ -2245,18 +2283,35 @@
}
}
- private class AccessibilityConnectionWrapper implements DeathRecipient {
+ class RemoteAccessibilityConnection implements DeathRecipient {
+ private final int mUid;
+ private final String mPackageName;
private final int mWindowId;
private final int mUserId;
private final IAccessibilityInteractionConnection mConnection;
- public AccessibilityConnectionWrapper(int windowId,
- IAccessibilityInteractionConnection connection, int userId) {
+ RemoteAccessibilityConnection(int windowId,
+ IAccessibilityInteractionConnection connection,
+ String packageName, int uid, int userId) {
mWindowId = windowId;
+ mPackageName = packageName;
+ mUid = uid;
mUserId = userId;
mConnection = connection;
}
+ public int getUid() {
+ return mUid;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public IAccessibilityInteractionConnection getRemote() {
+ return mConnection;
+ }
+
public void linkToDeath() throws RemoteException {
mConnection.asBinder().linkToDeath(this, 0);
}
@@ -2513,11 +2568,13 @@
long accessibilityNodeId, int action, Bundle arguments, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int fetchFlags,
long interrogatingTid) {
- IAccessibilityInteractionConnection connection = null;
+ RemoteAccessibilityConnection connection;
IBinder activityToken = null;
synchronized (mLock) {
connection = getConnectionLocked(resolvedWindowId);
- if (connection == null) return false;
+ if (connection == null) {
+ return false;
+ }
final boolean isA11yFocusAction = (action == ACTION_ACCESSIBILITY_FOCUS)
|| (action == ACTION_CLEAR_ACCESSIBILITY_FOCUS);
final AccessibilityWindowInfo a11yWindowInfo =
@@ -2529,7 +2586,7 @@
}
if ((a11yWindowInfo != null) && a11yWindowInfo.isInPictureInPictureMode()
&& (mPictureInPictureActionReplacingConnection != null) && !isA11yFocusAction) {
- connection = mPictureInPictureActionReplacingConnection.mConnection;
+ connection = mPictureInPictureActionReplacingConnection;
}
}
final int interrogatingPid = Binder.getCallingPid();
@@ -2544,8 +2601,9 @@
LocalServices.getService(ActivityManagerInternal.class)
.setFocusedActivity(activityToken);
}
- connection.performAccessibilityAction(accessibilityNodeId, action, arguments,
- interactionId, callback, fetchFlags, interrogatingPid, interrogatingTid);
+ connection.mConnection.performAccessibilityAction(accessibilityNodeId, action,
+ arguments, interactionId, callback, fetchFlags, interrogatingPid,
+ interrogatingTid);
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling performAccessibilityAction: " + re);
@@ -2558,17 +2616,17 @@
}
@Override
- public IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
+ public RemoteAccessibilityConnection getConnectionLocked(int windowId) {
if (DEBUG) {
Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
}
- AccessibilityManagerService.AccessibilityConnectionWrapper wrapper =
+ RemoteAccessibilityConnection connection =
mGlobalInteractionConnections.get(windowId);
- if (wrapper == null) {
- wrapper = getCurrentUserStateLocked().mInteractionConnections.get(windowId);
+ if (connection == null) {
+ connection = getCurrentUserStateLocked().mInteractionConnections.get(windowId);
}
- if (wrapper != null && wrapper.mConnection != null) {
- return wrapper.mConnection;
+ if (connection != null && connection.mConnection != null) {
+ return connection;
}
if (DEBUG) {
Slog.e(LOG_TAG, "No interaction connection to window: " + windowId);
@@ -2601,6 +2659,16 @@
}
}
+ private AppWidgetManagerInternal getAppWidgetManager() {
+ synchronized (mLock) {
+ if (mAppWidgetService == null
+ && mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
+ mAppWidgetService = LocalServices.getService(AppWidgetManagerInternal.class);
+ }
+ return mAppWidgetService;
+ }
+ }
+
final class WindowsForAccessibilityCallback implements
WindowManagerInternal.WindowsForAccessibilityCallback {
@@ -2893,6 +2961,78 @@
}
}
+ private boolean isValidPackageForUid(String packageName, int uid) {
+ try {
+ return uid == mPackageManager.getPackageUidAsUser(
+ packageName, UserHandle.getUserId(uid));
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ String resolveValidReportedPackageLocked(CharSequence packageName, int appId, int userId) {
+ // Okay to pass no package
+ if (packageName == null) {
+ return null;
+ }
+ // The system gets to pass any package
+ if (appId == Process.SYSTEM_UID) {
+ return packageName.toString();
+ }
+ // Passing a package in your UID is fine
+ final String packageNameStr = packageName.toString();
+ final int resolvedUid = UserHandle.getUid(userId, appId);
+ if (isValidPackageForUid(packageNameStr, resolvedUid)) {
+ return packageName.toString();
+ }
+ // Appwidget hosts get to pass packages for widgets they host
+ final AppWidgetManagerInternal appWidgetManager = getAppWidgetManager();
+ if (appWidgetManager != null && ArrayUtils.contains(appWidgetManager
+ .getHostedWidgetPackages(resolvedUid), packageNameStr)) {
+ return packageName.toString();
+ }
+ // Otherwise, set the package to the first one in the UID
+ final String[] packageNames = mPackageManager.getPackagesForUid(resolvedUid);
+ if (ArrayUtils.isEmpty(packageNames)) {
+ return null;
+ }
+ // Okay, the caller reported a package it does not have access to.
+ // Instead of crashing the caller for better backwards compatibility
+ // we report the first package in the UID. Since most of the time apps
+ // don't use shared user id, this will yield correct results and for
+ // the edge case of using a shared user id we may report the wrong
+ // package but this is fine since first, this is a cheating app and
+ // second there is no way to get the correct package anyway.
+ return packageNames[0];
+ }
+
+ String[] computeValidReportedPackages(int callingUid,
+ String targetPackage, int targetUid) {
+ if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
+ // Empty array means any package is Okay
+ return EmptyArray.STRING;
+ }
+ // IMPORTANT: The target package is already vetted to be in the target UID
+ String[] uidPackages = new String[]{targetPackage};
+ // Appwidget hosts get to pass packages for widgets they host
+ final AppWidgetManagerInternal appWidgetManager = getAppWidgetManager();
+ if (appWidgetManager != null) {
+ final ArraySet<String> widgetPackages = appWidgetManager
+ .getHostedWidgetPackages(targetUid);
+ if (widgetPackages != null && !widgetPackages.isEmpty()) {
+ final String[] validPackages = new String[uidPackages.length
+ + widgetPackages.size()];
+ System.arraycopy(uidPackages, 0, validPackages, 0, uidPackages.length);
+ final int widgetPackageCount = widgetPackages.size();
+ for (int i = 0; i < widgetPackageCount; i++) {
+ validPackages[uidPackages.length + i] = widgetPackages.valueAt(i);
+ }
+ return validPackages;
+ }
+ }
+ return uidPackages;
+ }
+
public void clearWindowsLocked() {
List<WindowInfo> windows = Collections.emptyList();
final int activeWindowId = mActiveWindowId;
@@ -3319,7 +3459,7 @@
public final RemoteCallbackList<IAccessibilityManagerClient> mUserClients =
new RemoteCallbackList<>();
- public final SparseArray<AccessibilityConnectionWrapper> mInteractionConnections =
+ public final SparseArray<RemoteAccessibilityConnection> mInteractionConnections =
new SparseArray<>();
public final SparseArray<IBinder> mWindowTokens = new SparseArray<>();
diff --git a/services/appwidget/Android.bp b/services/appwidget/Android.bp
new file mode 100644
index 0000000..aad2ad19
--- /dev/null
+++ b/services/appwidget/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+ name: "services.appwidget",
+ srcs: ["java/**/*.java"],
+ libs: ["services.core"],
+}
diff --git a/services/appwidget/Android.mk b/services/appwidget/Android.mk
deleted file mode 100644
index e9bab4a..0000000
--- a/services/appwidget/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services.appwidget
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,java)
-
-LOCAL_JAVA_LIBRARIES := services.core
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 6c15438..54cf726 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -32,6 +32,7 @@
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener;
import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetManagerInternal;
import android.appwidget.AppWidgetProviderInfo;
import android.appwidget.PendingHostUpdate;
import android.content.BroadcastReceiver;
@@ -100,6 +101,8 @@
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.widget.IRemoteViewsFactory;
@@ -107,6 +110,7 @@
import com.android.server.WidgetBackupProvider;
import com.android.server.policy.IconUtilities;
+import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -259,6 +263,8 @@
computeMaximumWidgetBitmapMemory();
registerBroadcastReceiver();
registerOnCrossProfileProvidersChangedListener();
+
+ LocalServices.addService(AppWidgetManagerInternal.class, new AppWidgetManagerLocal());
}
private void computeMaximumWidgetBitmapMemory() {
@@ -2506,6 +2512,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) {
@@ -4628,4 +4636,24 @@
}
}
}
+
+ private class AppWidgetManagerLocal extends AppWidgetManagerInternal {
+ @Override
+ public ArraySet<String> getHostedWidgetPackages(int uid) {
+ synchronized (mLock) {
+ ArraySet<String> widgetPackages = null;
+ final int widgetCount = mWidgets.size();
+ for (int i = 0; i < widgetCount; i++) {
+ final Widget widget = mWidgets.get(i);
+ if (widget.host.id.uid == uid) {
+ if (widgetPackages == null) {
+ widgetPackages = new ArraySet<>();
+ }
+ widgetPackages.add(widget.provider.id.componentName.getPackageName());
+ }
+ }
+ return widgetPackages;
+ }
+ }
+ }
}
diff --git a/services/autofill/Android.bp b/services/autofill/Android.bp
new file mode 100644
index 0000000..2768c18
--- /dev/null
+++ b/services/autofill/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+ name: "services.autofill",
+ srcs: ["java/**/*.java"],
+ libs: ["services.core"],
+}
diff --git a/services/autofill/Android.mk b/services/autofill/Android.mk
deleted file mode 100644
index a1f19fd..0000000
--- a/services/autofill/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services.autofill
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,java)
-
-LOCAL_JAVA_LIBRARIES := services.core
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
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..4bf3c5a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -26,31 +26,38 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.IActivityManager;
import android.content.ComponentName;
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;
+import android.metrics.LogMaker;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
+import android.os.Process;
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;
@@ -69,6 +76,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.HandlerCaller;
+import com.android.server.LocalServices;
import com.android.server.autofill.ui.AutoFillUI;
import java.io.PrintWriter;
@@ -121,6 +129,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 +196,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();
@@ -334,7 +355,7 @@
pruneAbandonedSessionsLocked();
final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken,
- hasCallback, componentName);
+ hasCallback, componentName, flags);
if (newSession == null) {
return NO_SESSION;
}
@@ -435,7 +456,7 @@
private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid,
@NonNull IBinder appCallbackToken, boolean hasCallback,
- @NonNull ComponentName componentName) {
+ @NonNull ComponentName componentName, int flags) {
// use random ids so that one app cannot know that another app creates sessions
int sessionId;
int tries = 0;
@@ -449,15 +470,46 @@
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);
+ mUiLatencyHistory, mInfo.getServiceInfo().getComponentName(), componentName, flags);
mSessions.put(newSession.id, newSession);
return newSession;
}
/**
+ * Asserts the component is owned by the caller.
+ */
+ private void assertCallerLocked(@NonNull ComponentName componentName) {
+ final String packageName = componentName.getPackageName();
+ final PackageManager pm = mContext.getPackageManager();
+ final int callingUid = Binder.getCallingUid();
+ final int packageUid;
+ try {
+ packageUid = pm.getPackageUidAsUser(packageName, UserHandle.getCallingUserId());
+ } catch (NameNotFoundException e) {
+ throw new SecurityException("Could not verify UID for " + componentName);
+ }
+ if (callingUid != packageUid && !LocalServices.getService(ActivityManagerInternal.class)
+ .hasRunningActivity(callingUid, packageName)) {
+ 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 +626,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 +664,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 +678,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 +690,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 +704,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 +719,38 @@
@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,
+ @NonNull String appPackageName) {
+
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);
+
+ final int size = detectedMatchesList.size();
+ float totalScore = 0;
+ for (int i = 0; i < size; i++) {
+ totalScore += detectedMatches[i].getScore();
+ }
+ final int averageScore = (int) ((totalScore * 100) / size);
+ mMetricsLogger.write(
+ Helper.newLogMaker(MetricsEvent.AUTOFILL_FIELD_CLASSIFICATION_MATCHES,
+ appPackageName, getServicePackageName())
+ .setCounterValue(size)
+ .addTaggedData(MetricsEvent.FIELD_AUTOFILL_MATCH_SCORE, averageScore));
+
+ }
mEventHistory.addEvent(new Event(Event.TYPE_CONTEXT_COMMITTED, null,
clientState, selectedDatasets, ignoredDatasets,
changedFieldIds, changedDatasetIds,
manuallyFilledFieldIds, manuallyFilledDatasetIds,
- detectedRemoteId, detectedFieldScore));
+ detectedFieldsIds, detectedMatches));
}
}
}
@@ -688,18 +764,59 @@
*/
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;
+ // Log it
+ int numberFields = mUserData == null ? 0: mUserData.getRemoteIds().length;
+ mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED,
+ getServicePackageName(), null)
+ .setCounterValue(numberFields));
+ }
+ }
+ }
+
+ 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 +824,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 +880,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 +902,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() {
@@ -905,10 +1036,12 @@
expiration = Long.MAX_VALUE;
}
mDisabledActivities.put(componentName, expiration);
- int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration;
- mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_ACTIVITY,
- componentName.getPackageName(), getServicePackageName())
- .addTaggedData(MetricsEvent.FIELD_CLASS_NAME, componentName.getClassName())
+ final int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration;
+ // NOTE: not using Helper.newLogMaker() because we're setting the componentName instead
+ // of package name
+ mMetricsLogger.write(new LogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_ACTIVITY)
+ .setComponentName(componentName)
+ .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, getServicePackageName())
.setCounterValue(intDuration));
}
}
@@ -926,7 +1059,8 @@
if (expiration >= elapsedTime) return true;
// Restriction expired - clean it up.
if (sVerbose) {
- Slog.v(TAG, "Removing " + componentName.toShortString() + " from disabled list");
+ Slog.v(TAG, "Removing " + componentName.toShortString()
+ + " from disabled list");
}
mDisabledActivities.remove(componentName);
}
@@ -951,10 +1085,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..56f5f64 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;
@@ -126,6 +128,9 @@
/** uid the session is for */
public final int uid;
+ /** Flags used to start the session */
+ public final int mFlags;
+
@GuardedBy("mLock")
@NonNull private IBinder mActivityToken;
@@ -236,6 +241,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.
@@ -429,8 +444,10 @@
@NonNull Context context, @NonNull HandlerCaller handlerCaller, int userId,
@NonNull Object lock, int sessionId, int uid, @NonNull IBinder activityToken,
@NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
- @NonNull ComponentName serviceComponentName, @NonNull ComponentName componentName) {
+ @NonNull ComponentName serviceComponentName, @NonNull ComponentName componentName,
+ int flags) {
id = sessionId;
+ mFlags = flags;
this.uid = uid;
mStartTime = SystemClock.elapsedRealtime();
mService = service;
@@ -444,7 +461,8 @@
mComponentName = componentName;
mClient = IAutoFillManagerClient.Stub.asInterface(client);
- writeLog(MetricsEvent.AUTOFILL_SESSION_STARTED);
+ mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
+ .addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
}
/**
@@ -480,7 +498,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: "
@@ -493,14 +511,15 @@
}
}
- // TODO(b/67867469): remove once feature is finished
- if (response.getFieldsDetection() != null && !mService.isFieldDetectionEnabled()) {
+ final AutofillId[] fieldClassificationIds = response.getFieldClassificationIds();
+ // TODO(b/67867469): remove once feature is finished (or use method from AFM to check)
+ if (fieldClassificationIds != 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();
@@ -536,6 +555,10 @@
.setType(MetricsEvent.TYPE_SUCCESS)
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
response.getDatasets() == null ? 0 : response.getDatasets().size());
+ if (fieldClassificationIds != null) {
+ log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS,
+ fieldClassificationIds.length);
+ }
mMetricsLogger.write(log);
}
@@ -903,7 +926,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 +949,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 +1015,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 +1077,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 +1093,8 @@
+ ", changedAutofillIds=" + changedFieldIds
+ ", changedDatasetIds=" + changedDatasetIds
+ ", manuallyFilledIds=" + manuallyFilledIds
- + ", detectableFieldId=" + detectableFieldId
- + ", detectedFieldScore=" + detectedFieldScore
+ + ", detectedFieldIds=" + detectedFieldIds
+ + ", detectedMatches=" + detectedMatches
);
}
@@ -1101,7 +1117,46 @@
mService.logContextCommitted(id, mClientState, mSelectedDatasetIds, ignoredDatasets,
changedFieldIds, changedDatasetIds,
manuallyFilledFieldIds, manuallyFilledDatasetIds,
- detectedRemoteId, detectedFieldScore);
+ detectedFieldIds, detectedMatches, mComponentName.getPackageName());
+ }
+
+ /**
+ * 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 +1722,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);
@@ -2071,6 +2126,7 @@
final String prefix2 = prefix + " ";
pw.print(prefix); pw.print("id: "); pw.println(id);
pw.print(prefix); pw.print("uid: "); pw.println(uid);
+ pw.print(prefix); pw.print("flags: "); pw.println(mFlags);
pw.print(prefix); pw.print("mComponentName: "); pw.println(mComponentName);
pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
pw.print(prefix); pw.print("mStartTime: "); pw.println(mStartTime);
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/Android.bp b/services/backup/Android.bp
new file mode 100644
index 0000000..ef03d83
--- /dev/null
+++ b/services/backup/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+ name: "services.backup",
+ srcs: ["java/**/*.java"],
+ libs: ["services.core"],
+}
diff --git a/services/backup/Android.mk b/services/backup/Android.mk
deleted file mode 100644
index 3e686d1..0000000
--- a/services/backup/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services.backup
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,java)
-
-LOCAL_JAVA_LIBRARIES := services.core
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
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..4adcb99 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) {
@@ -1496,7 +1520,11 @@
}
// clear an application's data, blocking until the operation completes or times out
- public void clearApplicationDataSynchronous(String packageName) {
+ // if keepSystemState is true, we intentionally do not also clear system state that
+ // would ordinarily also be cleared, because we aren't actually wiping the app back
+ // to empty; we're bringing it into the actual expected state related to the already-
+ // restored notification state etc.
+ public void clearApplicationDataSynchronous(String packageName, boolean keepSystemState) {
// Don't wipe packages marked allowClearUserData=false
try {
PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
@@ -1517,7 +1545,7 @@
synchronized (mClearDataLock) {
mClearingData = true;
try {
- mActivityManager.clearApplicationUserData(packageName, observer, 0);
+ mActivityManager.clearApplicationUserData(packageName, keepSystemState, observer, 0);
} catch (RemoteException e) {
// can't happen because the activity manager is in this process
}
@@ -2365,19 +2393,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 +2918,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) {
@@ -3122,10 +3242,10 @@
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");
+ TransportClient transportClient =
+ mTransportManager.getCurrentTransportClient("BMS.restoreAtInstall()");
+ if (transportClient == null) {
+ if (DEBUG) Slog.w(TAG, "No transport client");
skip = true;
}
@@ -3142,16 +3262,26 @@
// 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();
+
+ OnTaskFinishedListener listener = caller -> {
+ mTransportManager.disposeOfTransportClient(transportClient, caller);
+ mWakelock.release();
+ };
+
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);
+ msg.obj =
+ RestoreParams.createForRestoreAtInstall(
+ transportClient,
+ /* observer */ null,
+ /* monitor */ null,
+ restoreSet,
+ packageName,
+ token,
+ listener);
mBackupHandler.sendMessage(msg);
} catch (Exception e) {
// Calling into the transport broke; back off and proceed with the installation.
@@ -3161,8 +3291,14 @@
}
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.
+ // Auto-restore disabled or no way to attempt a restore
+
+ if (transportClient != null) {
+ mTransportManager.disposeOfTransportClient(
+ transportClient, "BMS.restoreAtInstall()");
+ }
+
+ // Tell the PackageManager to proceed with the post-install handling for this package.
if (DEBUG) Slog.v(TAG, "Finishing install immediately");
try {
mPackageManagerBinder.finishPackageInstall(token, false);
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..1f3ebf9 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,70 @@
}
/**
- * 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);
+ }
+
+ public boolean isTransportRegistered(String transportName) {
+ synchronized (mTransportLock) {
+ return getRegisteredTransportEntryLocked(transportName) != null;
+ }
}
/**
@@ -285,14 +351,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 +434,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 +515,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 +534,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 +576,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 +601,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 +614,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 +759,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..4c78348 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -189,7 +189,7 @@
}
task.execute();
} catch (ClassCastException e) {
- Slog.e(TAG, "Invalid backup task in flight, obj=" + msg.obj);
+ Slog.e(TAG, "Invalid backup/restore task in flight, obj=" + msg.obj);
}
break;
}
@@ -229,10 +229,18 @@
RestoreParams params = (RestoreParams) msg.obj;
Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
- PerformUnifiedRestoreTask task = new PerformUnifiedRestoreTask(backupManagerService,
- params.transport,
- params.observer, params.monitor, params.token, params.pkgInfo,
- params.pmToken, params.isSystemRestore, params.filterSet);
+ PerformUnifiedRestoreTask task =
+ new PerformUnifiedRestoreTask(
+ backupManagerService,
+ params.transportClient,
+ params.observer,
+ params.monitor,
+ params.token,
+ params.packageInfo,
+ params.pmToken,
+ params.isSystemRestore,
+ params.filterSet,
+ params.listener);
synchronized (backupManagerService.getPendingRestores()) {
if (backupManagerService.isRestoreInProgress()) {
@@ -268,8 +276,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;
}
@@ -294,8 +307,11 @@
// Like other async operations, this is entered with the wakelock held
RestoreSet[] sets = null;
RestoreGetSetsParams params = (RestoreGetSetsParams) msg.obj;
+ String callerLogString = "BH/MSG_RUN_GET_RESTORE_SETS";
try {
- sets = params.transport.getAvailableRestoreSets();
+ IBackupTransport transport =
+ params.transportClient.connectOrThrow(callerLogString);
+ sets = transport.getAvailableRestoreSets();
// cache the result in the active session
synchronized (params.session) {
params.session.mRestoreSets = sets;
@@ -320,7 +336,7 @@
removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
- backupManagerService.getWakelock().release();
+ params.listener.onFinished(callerLogString);
}
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..a002334 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 {
@@ -907,7 +907,7 @@
mStatus = BackupTransport.TRANSPORT_OK;
long size = 0;
try {
- TransportUtils.checkTransport(transport);
+ TransportUtils.checkTransportNotNull(transport);
size = mBackupDataName.length();
if (size > 0) {
if (mStatus == BackupTransport.TRANSPORT_OK) {
@@ -997,7 +997,7 @@
}
if (mAgentBinder != null) {
try {
- TransportUtils.checkTransport(transport);
+ TransportUtils.checkTransportNotNull(transport);
long quota = transport.getBackupQuota(mCurrentPackage.packageName, false);
mAgentBinder.doQuotaExceeded(size, quota);
} catch (Exception e) {
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/params/RestoreGetSetsParams.java b/services/backup/java/com/android/server/backup/params/RestoreGetSetsParams.java
index bff476b..914e9ea 100644
--- a/services/backup/java/com/android/server/backup/params/RestoreGetSetsParams.java
+++ b/services/backup/java/com/android/server/backup/params/RestoreGetSetsParams.java
@@ -20,20 +20,24 @@
import android.app.backup.IRestoreObserver;
import com.android.internal.backup.IBackupTransport;
+import com.android.server.backup.internal.OnTaskFinishedListener;
import com.android.server.backup.restore.ActiveRestoreSession;
+import com.android.server.backup.transport.TransportClient;
public class RestoreGetSetsParams {
+ public final TransportClient transportClient;
+ public final ActiveRestoreSession session;
+ public final IRestoreObserver observer;
+ public final IBackupManagerMonitor monitor;
+ public final OnTaskFinishedListener listener;
- public IBackupTransport transport;
- public ActiveRestoreSession session;
- public IRestoreObserver observer;
- public IBackupManagerMonitor monitor;
-
- public RestoreGetSetsParams(IBackupTransport _transport, ActiveRestoreSession _session,
- IRestoreObserver _observer, IBackupManagerMonitor _monitor) {
- transport = _transport;
+ public RestoreGetSetsParams(TransportClient _transportClient, ActiveRestoreSession _session,
+ IRestoreObserver _observer, IBackupManagerMonitor _monitor,
+ OnTaskFinishedListener _listener) {
+ transportClient = _transportClient;
session = _session;
observer = _observer;
monitor = _monitor;
+ listener = _listener;
}
}
diff --git a/services/backup/java/com/android/server/backup/params/RestoreParams.java b/services/backup/java/com/android/server/backup/params/RestoreParams.java
index 93ce00d..e500d6e 100644
--- a/services/backup/java/com/android/server/backup/params/RestoreParams.java
+++ b/services/backup/java/com/android/server/backup/params/RestoreParams.java
@@ -20,84 +20,128 @@
import android.app.backup.IRestoreObserver;
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 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;
+ public final TransportClient transportClient;
+ public final IRestoreObserver observer;
+ public final IBackupManagerMonitor monitor;
+ public final long token;
+ public final PackageInfo packageInfo;
+ public final int pmToken; // in post-install restore, the PM's token for this transaction
+ public final boolean isSystemRestore;
+ public final String[] filterSet;
+ public final OnTaskFinishedListener listener;
/**
- * Restore a single package; no kill after restore
+ * No kill after restore.
*/
- public 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;
+ public static RestoreParams createForSinglePackage(
+ TransportClient transportClient,
+ IRestoreObserver observer,
+ IBackupManagerMonitor monitor,
+ long token,
+ PackageInfo packageInfo,
+ OnTaskFinishedListener listener) {
+ return new RestoreParams(
+ transportClient,
+ observer,
+ monitor,
+ token,
+ packageInfo,
+ /* pmToken */ 0,
+ /* isSystemRestore */ false,
+ /* filterSet */ null,
+ listener);
}
/**
- * Restore at install: PM token needed, kill after restore
+ * Kill after restore.
*/
- public 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};
+ public static RestoreParams createForRestoreAtInstall(
+ TransportClient transportClient,
+ IRestoreObserver observer,
+ IBackupManagerMonitor monitor,
+ long token,
+ String packageName,
+ int pmToken,
+ OnTaskFinishedListener listener) {
+ String[] filterSet = {packageName};
+ return new RestoreParams(
+ transportClient,
+ observer,
+ monitor,
+ token,
+ /* packageInfo */ null,
+ pmToken,
+ /* isSystemRestore */ false,
+ filterSet,
+ listener);
}
/**
- * Restore everything possible. This is the form that Setup Wizard or similar
- * restore UXes use.
+ * This is the form that Setup Wizard or similar restore UXes use.
*/
- public 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;
+ public static RestoreParams createForRestoreAll(
+ TransportClient transportClient,
+ IRestoreObserver observer,
+ IBackupManagerMonitor monitor,
+ long token,
+ OnTaskFinishedListener listener) {
+ return new RestoreParams(
+ transportClient,
+ observer,
+ monitor,
+ token,
+ /* packageInfo */ null,
+ /* pmToken */ 0,
+ /* isSystemRestore */ true,
+ /* filterSet */ null,
+ listener);
}
/**
- * Restore some set of packages. Leave this one up to the caller to specify
- * whether it's to be considered a system-level restore.
+ * Caller specifies whether is considered a system-level restore.
*/
- public 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;
+ public static RestoreParams createForRestoreSome(
+ TransportClient transportClient,
+ IRestoreObserver observer,
+ IBackupManagerMonitor monitor,
+ long token,
+ String[] filterSet,
+ boolean isSystemRestore,
+ OnTaskFinishedListener listener) {
+ return new RestoreParams(
+ transportClient,
+ observer,
+ monitor,
+ token,
+ /* packageInfo */ null,
+ /* pmToken */ 0,
+ isSystemRestore,
+ filterSet,
+ listener);
+ }
+
+ private RestoreParams(
+ TransportClient transportClient,
+ IRestoreObserver observer,
+ IBackupManagerMonitor monitor,
+ long token,
+ PackageInfo packageInfo,
+ int pmToken,
+ boolean isSystemRestore,
+ String[] filterSet,
+ OnTaskFinishedListener listener) {
+ this.transportClient = transportClient;
+ this.observer = observer;
+ this.monitor = monitor;
+ this.token = token;
+ this.packageInfo = packageInfo;
+ this.pmToken = pmToken;
+ this.isSystemRestore = isSystemRestore;
+ this.filterSet = filterSet;
+ this.listener = listener;
}
}
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index a08c19e..7ae5b43 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -31,33 +31,39 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
import android.os.Message;
+import android.os.PowerManager;
import android.util.Slog;
-import com.android.internal.backup.IBackupTransport;
import com.android.server.backup.RefactoredBackupManagerService;
+import com.android.server.backup.TransportManager;
+import com.android.server.backup.internal.BackupHandler;
+import com.android.server.backup.internal.OnTaskFinishedListener;
import com.android.server.backup.params.RestoreGetSetsParams;
import com.android.server.backup.params.RestoreParams;
+import com.android.server.backup.transport.TransportClient;
+
+import java.util.function.BiFunction;
/**
* Restore session.
*/
public class ActiveRestoreSession extends IRestoreSession.Stub {
-
private static final String TAG = "RestoreSession";
- private RefactoredBackupManagerService backupManagerService;
- private String mPackageName;
- private IBackupTransport mRestoreTransport = null;
+ private final TransportManager mTransportManager;
+ private final String mTransportName;
+ private final RefactoredBackupManagerService mBackupManagerService;
+ private final String mPackageName;
public RestoreSet[] mRestoreSets = null;
boolean mEnded = false;
boolean mTimedOut = false;
public ActiveRestoreSession(RefactoredBackupManagerService backupManagerService,
- String packageName, String transport) {
- this.backupManagerService = backupManagerService;
+ String packageName, String transportName) {
+ mBackupManagerService = backupManagerService;
mPackageName = packageName;
- mRestoreTransport = backupManagerService.getTransportManager().getTransportBinder(
- transport);
+ mTransportManager = backupManagerService.getTransportManager();
+ mTransportName = transportName;
}
public void markTimedOut() {
@@ -67,7 +73,7 @@
// --- Binder interface ---
public synchronized int getAvailableRestoreSets(IRestoreObserver observer,
IBackupManagerMonitor monitor) {
- backupManagerService.getContext().enforceCallingOrSelfPermission(
+ mBackupManagerService.getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP,
"getAvailableRestoreSets");
if (observer == null) {
@@ -85,23 +91,32 @@
long oldId = Binder.clearCallingIdentity();
try {
- if (mRestoreTransport == null) {
- Slog.w(TAG, "Null transport getting restore sets");
+ TransportClient transportClient =
+ mTransportManager.getTransportClient(
+ mTransportName, "RestoreSession.getAvailableRestoreSets()");
+ if (transportClient == null) {
+ Slog.w(TAG, "Null transport client 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.
- backupManagerService.getBackupHandler().removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
+ mBackupManagerService.getBackupHandler().removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
- // spin off the transport request to our service thread
- backupManagerService.getWakelock().acquire();
- Message msg = backupManagerService.getBackupHandler().obtainMessage(
+ PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock();
+ wakelock.acquire();
+
+ // Prevent lambda from leaking 'this'
+ TransportManager transportManager = mTransportManager;
+ OnTaskFinishedListener listener = caller -> {
+ transportManager.disposeOfTransportClient(transportClient, caller);
+ wakelock.release();
+ };
+ Message msg = mBackupManagerService.getBackupHandler().obtainMessage(
MSG_RUN_GET_RESTORE_SETS,
- new RestoreGetSetsParams(mRestoreTransport, this, observer,
- monitor));
- backupManagerService.getBackupHandler().sendMessage(msg);
+ new RestoreGetSetsParams(transportClient, this, observer, monitor, listener));
+ mBackupManagerService.getBackupHandler().sendMessage(msg);
return 0;
} catch (Exception e) {
Slog.e(TAG, "Error in getAvailableRestoreSets", e);
@@ -113,7 +128,7 @@
public synchronized int restoreAll(long token, IRestoreObserver observer,
IBackupManagerMonitor monitor) {
- backupManagerService.getContext().enforceCallingOrSelfPermission(
+ mBackupManagerService.getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP,
"performRestore");
@@ -131,7 +146,7 @@
return -1;
}
- if (mRestoreTransport == null || mRestoreSets == null) {
+ if (mRestoreSets == null) {
Slog.e(TAG, "Ignoring restoreAll() with no restore set");
return -1;
}
@@ -141,37 +156,28 @@
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());
+ if (!mTransportManager.isTransportRegistered(mTransportName)) {
+ Slog.e(TAG, "Transport " + mTransportName + " not registered");
return -1;
}
- synchronized (backupManagerService.getQueueLock()) {
+ synchronized (mBackupManagerService.getQueueLock()) {
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
- backupManagerService.getBackupHandler().removeMessages(
- MSG_RESTORE_SESSION_TIMEOUT);
-
long oldId = Binder.clearCallingIdentity();
try {
- backupManagerService.getWakelock().acquire();
- if (MORE_DEBUG) {
- Slog.d(TAG, "restoreAll() kicking off");
- }
- Message msg = backupManagerService.getBackupHandler().obtainMessage(
- MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, dirName,
- observer, monitor, token);
- backupManagerService.getBackupHandler().sendMessage(msg);
+ return sendRestoreToHandlerLocked(
+ (transportClient, listener) ->
+ RestoreParams.createForRestoreAll(
+ transportClient,
+ observer,
+ monitor,
+ token,
+ listener),
+ "RestoreSession.restoreAll()");
} finally {
Binder.restoreCallingIdentity(oldId);
}
- return 0;
}
}
}
@@ -183,7 +189,7 @@
// Restores of more than a single package are treated as 'system' restores
public synchronized int restoreSome(long token, IRestoreObserver observer,
IBackupManagerMonitor monitor, String[] packages) {
- backupManagerService.getContext().enforceCallingOrSelfPermission(
+ mBackupManagerService.getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP,
"performRestore");
@@ -227,7 +233,7 @@
return -1;
}
- if (mRestoreTransport == null || mRestoreSets == null) {
+ if (mRestoreSets == null) {
Slog.e(TAG, "Ignoring restoreAll() with no restore set");
return -1;
}
@@ -237,34 +243,30 @@
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());
+ if (!mTransportManager.isTransportRegistered(mTransportName)) {
+ Slog.e(TAG, "Transport " + mTransportName + " not registered");
return -1;
}
- synchronized (backupManagerService.getQueueLock()) {
+ synchronized (mBackupManagerService.getQueueLock()) {
for (int i = 0; i < mRestoreSets.length; i++) {
if (token == mRestoreSets[i].token) {
- // Stop the session timeout until we finalize the restore
- backupManagerService.getBackupHandler().removeMessages(
- MSG_RESTORE_SESSION_TIMEOUT);
-
long oldId = Binder.clearCallingIdentity();
- backupManagerService.getWakelock().acquire();
- if (MORE_DEBUG) {
- Slog.d(TAG, "restoreSome() of " + packages.length + " packages");
+ try {
+ return sendRestoreToHandlerLocked(
+ (transportClient, listener) ->
+ RestoreParams.createForRestoreSome(
+ transportClient,
+ observer,
+ monitor,
+ token,
+ packages,
+ /* isSystemRestore */ packages.length > 1,
+ listener),
+ "RestoreSession.restoreSome(" + packages.length + " packages)");
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
}
- Message msg = backupManagerService.getBackupHandler().obtainMessage(
- MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, monitor,
- token, packages, packages.length > 1);
- backupManagerService.getBackupHandler().sendMessage(msg);
- Binder.restoreCallingIdentity(oldId);
- return 0;
}
}
}
@@ -297,9 +299,9 @@
}
}
- PackageInfo app = null;
+ final PackageInfo app;
try {
- app = backupManagerService.getPackageManager().getPackageInfo(packageName, 0);
+ app = mBackupManagerService.getPackageManager().getPackageInfo(packageName, 0);
} catch (NameNotFoundException nnf) {
Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
return -1;
@@ -307,7 +309,7 @@
// 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 = backupManagerService.getContext().checkPermission(
+ int perm = mBackupManagerService.getContext().checkPermission(
android.Manifest.permission.BACKUP,
Binder.getCallingPid(), Binder.getCallingUid());
if ((perm == PackageManager.PERMISSION_DENIED) &&
@@ -317,12 +319,17 @@
throw new SecurityException("No permission to restore other packages");
}
+ if (!mTransportManager.isTransportRegistered(mTransportName)) {
+ Slog.e(TAG, "Transport " + mTransportName + " not registered");
+ return -1;
+ }
+
// 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 = backupManagerService.getAvailableRestoreToken(packageName);
+ long token = mBackupManagerService.getAvailableRestoreToken(packageName);
if (DEBUG) {
Slog.v(TAG, "restorePackage pkg=" + packageName
+ " token=" + Long.toHexString(token));
@@ -338,30 +345,53 @@
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
- backupManagerService.getBackupHandler().removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
-
- // Ready to go: enqueue the restore request and claim success
- backupManagerService.getWakelock().acquire();
- if (MORE_DEBUG) {
- Slog.d(TAG, "restorePackage() : " + packageName);
- }
- Message msg = backupManagerService.getBackupHandler().obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, monitor,
- token, app);
- backupManagerService.getBackupHandler().sendMessage(msg);
+ return sendRestoreToHandlerLocked(
+ (transportClient, listener) ->
+ RestoreParams.createForSinglePackage(
+ transportClient,
+ observer,
+ monitor,
+ token,
+ app,
+ listener),
+ "RestoreSession.restorePackage(" + packageName + ")");
} finally {
Binder.restoreCallingIdentity(oldId);
}
+ }
+
+ /**
+ * Returns 0 if operation sent or -1 otherwise.
+ */
+ private int sendRestoreToHandlerLocked(
+ BiFunction<TransportClient, OnTaskFinishedListener, RestoreParams> restoreParamsBuilder,
+ String callerLogString) {
+ TransportClient transportClient =
+ mTransportManager.getTransportClient(mTransportName, callerLogString);
+ if (transportClient == null) {
+ Slog.e(TAG, "Transport " + mTransportName + " got unregistered");
+ return -1;
+ }
+
+ // Stop the session timeout until we finalize the restore
+ BackupHandler backupHandler = mBackupManagerService.getBackupHandler();
+ backupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
+
+ PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock();
+ wakelock.acquire();
+ if (MORE_DEBUG) {
+ Slog.d(TAG, callerLogString);
+ }
+
+ // Prevent lambda from leaking 'this'
+ TransportManager transportManager = mTransportManager;
+ OnTaskFinishedListener listener = caller -> {
+ transportManager.disposeOfTransportClient(transportClient, caller);
+ wakelock.release();
+ };
+ Message msg = backupHandler.obtainMessage(MSG_RUN_RESTORE);
+ msg.obj = restoreParamsBuilder.apply(transportClient, listener);
+ backupHandler.sendMessage(msg);
return 0;
}
@@ -380,7 +410,6 @@
public void run() {
// clean up the session's bookkeeping
synchronized (mSession) {
- mSession.mRestoreTransport = null;
mSession.mEnded = true;
}
@@ -404,7 +433,7 @@
throw new IllegalStateException("Restore session already ended");
}
- backupManagerService.getBackupHandler().post(
- new EndRestoreRunnable(backupManagerService, this));
+ mBackupManagerService.getBackupHandler().post(
+ new EndRestoreRunnable(mBackupManagerService, this));
}
}
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index 888dcd7e..7efe5ca 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -327,7 +327,7 @@
Slog.d(TAG,
"Clearing app data preparatory to full restore");
}
- mBackupManagerService.clearApplicationDataSynchronous(pkg);
+ mBackupManagerService.clearApplicationDataSynchronous(pkg, true);
} else {
if (MORE_DEBUG) {
Slog.d(TAG, "backup agent ("
diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
index 22691bb..3dc242f 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
@@ -591,7 +591,7 @@
Slog.d(TAG,
"Clearing app data preparatory to full restore");
}
- mBackupManagerService.clearApplicationDataSynchronous(pkg);
+ mBackupManagerService.clearApplicationDataSynchronous(pkg, true);
} else {
if (DEBUG) {
Slog.d(TAG, "backup agent ("
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..86866dc 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -61,6 +61,8 @@
import com.android.server.backup.PackageManagerBackupAgent;
import com.android.server.backup.PackageManagerBackupAgent.Metadata;
import com.android.server.backup.RefactoredBackupManagerService;
+import com.android.server.backup.internal.OnTaskFinishedListener;
+import com.android.server.backup.transport.TransportClient;
import com.android.server.backup.utils.AppBackupUtils;
import com.android.server.backup.utils.BackupManagerMonitorUtils;
@@ -76,8 +78,8 @@
public class PerformUnifiedRestoreTask implements BackupRestoreTask {
private RefactoredBackupManagerService backupManagerService;
- // Transport we're working with to do the restore
- private IBackupTransport mTransport;
+ // Transport client we're working with to do the restore
+ private final TransportClient mTransportClient;
// Where per-transport saved state goes
File mStateDir;
@@ -141,6 +143,9 @@
// Done?
private boolean mFinished;
+ // When finished call listener
+ private final OnTaskFinishedListener mListener;
+
// Key/value: bookkeeping about staged data and files for agent access
private File mBackupDataName;
private File mStageName;
@@ -154,15 +159,16 @@
// Invariant: mWakelock is already held, and this task is responsible for
// releasing it at the end of the restore operation.
public PerformUnifiedRestoreTask(RefactoredBackupManagerService backupManagerService,
- IBackupTransport transport, IRestoreObserver observer,
+ TransportClient transportClient, IRestoreObserver observer,
IBackupManagerMonitor monitor, long restoreSetToken, PackageInfo targetPackage,
- int pmToken, boolean isFullSystemRestore, String[] filterSet) {
+ int pmToken, boolean isFullSystemRestore, String[] filterSet,
+ OnTaskFinishedListener listener) {
this.backupManagerService = backupManagerService;
mEphemeralOpToken = backupManagerService.generateRandomIntegerToken();
mState = UnifiedRestoreState.INITIAL;
mStartRealtime = SystemClock.elapsedRealtime();
- mTransport = transport;
+ mTransportClient = transportClient;
mObserver = observer;
mMonitor = monitor;
mToken = restoreSetToken;
@@ -171,6 +177,7 @@
mIsSystemRestore = isFullSystemRestore;
mFinished = false;
mDidLaunch = false;
+ mListener = listener;
if (targetPackage != null) {
// Single package restore
@@ -342,7 +349,7 @@
}
try {
- String transportDir = mTransport.transportDirName();
+ String transportDir = mTransportClient.getTransportDirName();
mStateDir = new File(backupManagerService.getBaseStateDir(), transportDir);
// Fetch the current metadata from the dataset first
@@ -351,7 +358,11 @@
mAcceptSet.add(0, pmPackage);
PackageInfo[] packages = mAcceptSet.toArray(new PackageInfo[0]);
- mStatus = mTransport.startRestore(mToken, packages);
+
+ IBackupTransport transport =
+ mTransportClient.connectOrThrow("PerformUnifiedRestoreTask.startRestore()");
+
+ mStatus = transport.startRestore(mToken, packages);
if (mStatus != BackupTransport.TRANSPORT_OK) {
Slog.e(TAG, "Transport error " + mStatus + "; no restore possible");
mStatus = BackupTransport.TRANSPORT_ERROR;
@@ -359,7 +370,7 @@
return;
}
- RestoreDescription desc = mTransport.nextRestorePackage();
+ RestoreDescription desc = transport.nextRestorePackage();
if (desc == null) {
Slog.e(TAG, "No restore metadata available; halting");
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
@@ -444,7 +455,10 @@
private void dispatchNextRestore() {
UnifiedRestoreState nextState = UnifiedRestoreState.FINAL;
try {
- mRestoreDescription = mTransport.nextRestorePackage();
+ IBackupTransport transport =
+ mTransportClient.connectOrThrow(
+ "PerformUnifiedRestoreTask.dispatchNextRestore()");
+ mRestoreDescription = transport.nextRestorePackage();
final String pkgName = (mRestoreDescription != null)
? mRestoreDescription.getPackageName() : null;
if (pkgName == null) {
@@ -495,14 +509,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 +536,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 +557,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 +649,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) {
@@ -657,13 +671,17 @@
File downloadFile = (staging) ? mStageName : mBackupDataName;
try {
+ IBackupTransport transport =
+ mTransportClient.connectOrThrow(
+ "PerformUnifiedRestoreTask.initiateOneRestore()");
+
// 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) {
+ if (transport.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);
@@ -750,7 +768,7 @@
// None of this can run on the work looper here, so we spin asynchronous
// work like this:
//
- // StreamFeederThread: read data from mTransport.getNextFullRestoreDataChunk()
+ // StreamFeederThread: read data from transport.getNextFullRestoreDataChunk()
// write it into the pipe to the engine
// EngineThread: FullRestoreEngine thread communicating with the target app
//
@@ -844,10 +862,12 @@
// spin up the engine and start moving data to it
new Thread(mEngineThread, "unified-restore-engine").start();
+ String callerLogString = "PerformUnifiedRestoreTask$StreamFeederThread.run()";
try {
+ IBackupTransport transport = mTransportClient.connectOrThrow(callerLogString);
while (status == BackupTransport.TRANSPORT_OK) {
// have the transport write some of the restoring data to us
- int result = mTransport.getNextFullRestoreDataChunk(tWriteEnd);
+ int result = transport.getNextFullRestoreDataChunk(tWriteEnd);
if (result > 0) {
// The transport wrote this many bytes of restore data to the
// pipe, so pass it along to the engine.
@@ -936,7 +956,9 @@
// Something went wrong somewhere. Whether it was at the transport
// level is immaterial; we need to tell the transport to bail
try {
- mTransport.abortFullRestore();
+ IBackupTransport transport =
+ mTransportClient.connectOrThrow(callerLogString);
+ transport.abortFullRestore();
} catch (Exception e) {
// transport itself is dead; make sure we handle this as a
// fatal error
@@ -947,7 +969,7 @@
// We also need to wipe the current target's data, as it's probably
// in an incoherent state.
backupManagerService.clearApplicationDataSynchronous(
- mCurrentPackage.packageName);
+ mCurrentPackage.packageName, false);
// Schedule the next state based on the nature of our failure
if (status == BackupTransport.TRANSPORT_ERROR) {
@@ -1039,8 +1061,11 @@
Slog.d(TAG, "finishing restore mObserver=" + mObserver);
}
+ String callerLogString = "PerformUnifiedRestoreTask.finalizeRestore()";
try {
- mTransport.finishRestore();
+ IBackupTransport transport =
+ mTransportClient.connectOrThrow(callerLogString);
+ transport.finishRestore();
} catch (Exception e) {
Slog.e(TAG, "Error finishing restore", e);
}
@@ -1087,9 +1112,6 @@
backupManagerService.writeRestoreTokens();
}
- // done; we can finally release the wakelock and be legitimately done.
- Slog.i(TAG, "Restore complete.");
-
synchronized (backupManagerService.getPendingRestores()) {
if (backupManagerService.getPendingRestores().size() > 0) {
if (DEBUG) {
@@ -1108,14 +1130,15 @@
}
}
- backupManagerService.getWakelock().release();
+ Slog.i(TAG, "Restore complete.");
+ mListener.onFinished(callerLogString);
}
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
- backupManagerService.clearApplicationDataSynchronous(mCurrentPackage.packageName);
+ backupManagerService.clearApplicationDataSynchronous(mCurrentPackage.packageName, false);
keyValueAgentCleanup();
}
@@ -1301,13 +1324,11 @@
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;
- }
+ try {
+ mObserver.onUpdate(mCount, name);
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Restore observer died in onUpdate");
+ mObserver = null;
}
}
}
diff --git a/services/backup/java/com/android/server/backup/restore/RestoreEngine.java b/services/backup/java/com/android/server/backup/restore/RestoreEngine.java
index b2fdbb8..9d3ae86 100644
--- a/services/backup/java/com/android/server/backup/restore/RestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/RestoreEngine.java
@@ -30,8 +30,8 @@
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);
+ private final AtomicBoolean mRunning = new AtomicBoolean(false);
+ private final AtomicInteger mResult = new AtomicInteger(SUCCESS);
public boolean isRunning() {
return mRunning.get();
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/transport/TransportUtils.java b/services/backup/java/com/android/server/backup/transport/TransportUtils.java
index 85599b7..92bba9b 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportUtils.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportUtils.java
@@ -31,7 +31,7 @@
* Throws {@link TransportNotAvailableException} if {@param transport} is null. The semantics is
* similar to a {@link DeadObjectException} coming from a dead transport binder.
*/
- public static IBackupTransport checkTransport(@Nullable IBackupTransport transport)
+ public static IBackupTransport checkTransportNotNull(@Nullable IBackupTransport transport)
throws TransportNotAvailableException {
if (transport == null) {
log(Log.ERROR, TAG, "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/Android.bp b/services/companion/Android.bp
new file mode 100644
index 0000000..d2dac35
--- /dev/null
+++ b/services/companion/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+ name: "services.companion",
+ srcs: ["java/**/*.java"],
+ libs: ["services.core"],
+}
diff --git a/services/companion/Android.mk b/services/companion/Android.mk
deleted file mode 100644
index be48761..0000000
--- a/services/companion/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services.companion
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,java)
-
-LOCAL_JAVA_LIBRARIES := services.core
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
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/Android.bp b/services/core/Android.bp
new file mode 100644
index 0000000..a2505a8
--- /dev/null
+++ b/services/core/Android.bp
@@ -0,0 +1,62 @@
+java_library_static {
+ name: "services.core.unboosted",
+
+ aidl: {
+ include_dirs: [
+ "frameworks/native/aidl/binder",
+ "system/core/storaged/binder",
+ "system/netd/server/binder",
+ "system/vold/binder",
+ ],
+ },
+ srcs: [
+ "java/**/*.java",
+ ":netd_aidl",
+ ":netd_metrics_aidl",
+ ":installd_aidl",
+ ":storaged_aidl",
+ ":vold_aidl",
+ "java/com/android/server/EventLogTags.logtags",
+ "java/com/android/server/am/EventLogTags.logtags",
+ ],
+
+ libs: [
+ "services.net",
+ "android.hardware.light-V2.0-java",
+ "android.hardware.power-V1.0-java",
+ "android.hardware.tv.cec-V1.0-java",
+ "android.hidl.manager-V1.0-java",
+ ],
+
+ static_libs: [
+ "time_zone_distro",
+ "time_zone_distro_installer",
+ "android.hardware.health-V1.0-java",
+ "android.hardware.health-V2.0-java",
+ "android.hardware.weaver-V1.0-java",
+ "android.hardware.biometrics.fingerprint-V2.1-java",
+ "android.hardware.oemlock-V1.0-java",
+ "android.hardware.tetheroffload.control-V1.0-java",
+ "android.hardware.vibrator-V1.0-java",
+ "android.hardware.configstore-V1.0-java",
+ "android.hardware.contexthub-V1.0-java",
+ ],
+}
+
+java_genrule {
+ name: "services.core.priorityboosted",
+ srcs: [":services.core.unboosted"],
+ tools: ["lockedregioncodeinjection"],
+ cmd: "$(location lockedregioncodeinjection) " +
+ " --targets \"Lcom/android/server/am/ActivityManagerService;,Lcom/android/server/wm/WindowHashMap;\" " +
+ " --pre \"com/android/server/am/ActivityManagerService.boostPriorityForLockedSection,com/android/server/wm/WindowManagerService.boostPriorityForLockedSection\" " +
+ " --post \"com/android/server/am/ActivityManagerService.resetPriorityAfterLockedSection,com/android/server/wm/WindowManagerService.resetPriorityAfterLockedSection\" " +
+ " -o $(out) " +
+ " -i $(in)",
+ out: ["services.core.priorityboosted.jar"],
+}
+
+java_library {
+ name: "services.core",
+ static_libs: ["services.core.priorityboosted"],
+}
diff --git a/services/core/Android.mk b/services/core/Android.mk
deleted file mode 100644
index 3d81baf..0000000
--- a/services/core/Android.mk
+++ /dev/null
@@ -1,72 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services.core
-
-LOCAL_AIDL_INCLUDES := \
- frameworks/native/aidl/binder \
- system/core/storaged/binder \
- system/netd/server/binder \
- system/vold/binder
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,java) \
- java/com/android/server/EventLogTags.logtags \
- java/com/android/server/am/EventLogTags.logtags \
- ../../../../system/core/storaged/binder/android/os/IStoraged.aidl \
- ../../../../system/netd/server/binder/android/net/INetd.aidl \
- ../../../../system/netd/server/binder/android/net/metrics/INetdEventListener.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/netd/server/binder
-
-LOCAL_JAVA_LIBRARIES := \
- services.net \
- android.hardware.light-V2.0-java \
- android.hardware.power-V1.0-java \
- android.hardware.tv.cec-V1.0-java \
- android.hidl.manager-V1.0-java
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- time_zone_distro \
- time_zone_distro_installer \
- android.hidl.base-V1.0-java \
- android.hardware.health-V1.0-java \
- android.hardware.health-V2.0-java \
- android.hardware.weaver-V1.0-java \
- android.hardware.biometrics.fingerprint-V2.1-java \
- android.hardware.oemlock-V1.0-java \
- android.hardware.tetheroffload.control-V1.0-java \
- android.hardware.vibrator-V1.0-java \
- android.hardware.configstore-V1.0-java \
- android.hardware.contexthub-V1.0-java
-
-ifneq ($(INCREMENTAL_BUILDS),)
- LOCAL_PROGUARD_ENABLED := disabled
- LOCAL_JACK_ENABLED := incremental
-endif
-
-LOCAL_JACK_FLAGS := \
- -D jack.transformations.boost-locked-region-priority=true \
- -D jack.transformations.boost-locked-region-priority.classname=com.android.server.am.ActivityManagerService,com.android.server.wm.WindowHashMap \
- -D jack.transformations.boost-locked-region-priority.request=com.android.server.am.ActivityManagerService\#boostPriorityForLockedSection,com.android.server.wm.WindowManagerService\#boostPriorityForLockedSection \
- -D jack.transformations.boost-locked-region-priority.reset=com.android.server.am.ActivityManagerService\#resetPriorityAfterLockedSection,com.android.server.wm.WindowManagerService\#resetPriorityAfterLockedSection
-
-LOCAL_JAR_PROCESSOR := lockedregioncodeinjection
-# Use = instead of := to delay evaluation of ${in} and ${out}
-LOCAL_JAR_PROCESSOR_ARGS = \
- --targets \
- "Lcom/android/server/am/ActivityManagerService;,Lcom/android/server/wm/WindowHashMap;" \
- --pre \
- "com/android/server/am/ActivityManagerService.boostPriorityForLockedSection,com/android/server/wm/WindowManagerService.boostPriorityForLockedSection" \
- --post \
- "com/android/server/am/ActivityManagerService.resetPriorityAfterLockedSection,com/android/server/wm/WindowManagerService.resetPriorityAfterLockedSection" \
- -o ${out} \
- -i ${in}
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/services/core/java/com/android/server/AlarmManagerInternal.java
similarity index 71%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to services/core/java/com/android/server/AlarmManagerInternal.java
index 353728a..dbff957 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/services/core/java/com/android/server/AlarmManagerInternal.java
@@ -11,15 +11,11 @@
* 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.server.timezone;
+package com.android.server;
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
-
- long currentTimestamp();
+public interface AlarmManagerInternal {
+ void removeAlarmsForUid(int uid);
}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index ca15249..06cf982 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -92,6 +92,7 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.LocalLog;
import com.android.server.ForceAppStandbyTracker.Listener;
+import com.android.server.LocalServices;
/**
* Alarm manager implementaion.
@@ -467,21 +468,14 @@
return newStart;
}
- boolean remove(final PendingIntent operation, final IAlarmListener listener) {
- if (operation == null && listener == null) {
- if (localLOGV) {
- Slog.w(TAG, "requested remove() of null operation",
- new RuntimeException("here"));
- }
- return false;
- }
+ boolean remove(Predicate<Alarm> predicate) {
boolean didRemove = false;
long newStart = 0; // recalculate endpoints as we go
long newEnd = Long.MAX_VALUE;
int newFlags = 0;
for (int i = 0; i < alarms.size(); ) {
Alarm alarm = alarms.get(i);
- if (alarm.matches(operation, listener)) {
+ if (predicate.test(alarm)) {
alarms.remove(i);
didRemove = true;
if (alarm.alarmClock != null) {
@@ -507,111 +501,6 @@
return didRemove;
}
- boolean remove(final String packageName) {
- if (packageName == null) {
- if (localLOGV) {
- Slog.w(TAG, "requested remove() of null packageName",
- new RuntimeException("here"));
- }
- return false;
- }
- boolean didRemove = false;
- long newStart = 0; // recalculate endpoints as we go
- long newEnd = Long.MAX_VALUE;
- int newFlags = 0;
- for (int i = alarms.size()-1; i >= 0; i--) {
- Alarm alarm = alarms.get(i);
- if (alarm.matches(packageName)) {
- alarms.remove(i);
- didRemove = true;
- if (alarm.alarmClock != null) {
- mNextAlarmClockMayChange = true;
- }
- } else {
- if (alarm.whenElapsed > newStart) {
- newStart = alarm.whenElapsed;
- }
- if (alarm.maxWhenElapsed < newEnd) {
- newEnd = alarm.maxWhenElapsed;
- }
- newFlags |= alarm.flags;
- }
- }
- if (didRemove) {
- // commit the new batch bounds
- start = newStart;
- end = newEnd;
- flags = newFlags;
- }
- return didRemove;
- }
-
- boolean removeForStopped(final int uid) {
- boolean didRemove = false;
- long newStart = 0; // recalculate endpoints as we go
- long newEnd = Long.MAX_VALUE;
- int newFlags = 0;
- for (int i = alarms.size()-1; i >= 0; i--) {
- Alarm alarm = alarms.get(i);
- try {
- if (alarm.uid == uid && ActivityManager.getService().isAppStartModeDisabled(
- uid, alarm.packageName)) {
- alarms.remove(i);
- didRemove = true;
- if (alarm.alarmClock != null) {
- mNextAlarmClockMayChange = true;
- }
- } else {
- if (alarm.whenElapsed > newStart) {
- newStart = alarm.whenElapsed;
- }
- if (alarm.maxWhenElapsed < newEnd) {
- newEnd = alarm.maxWhenElapsed;
- }
- newFlags |= alarm.flags;
- }
- } catch (RemoteException e) {
- }
- }
- if (didRemove) {
- // commit the new batch bounds
- start = newStart;
- end = newEnd;
- flags = newFlags;
- }
- return didRemove;
- }
-
- boolean remove(final int userHandle) {
- boolean didRemove = false;
- long newStart = 0; // recalculate endpoints as we go
- long newEnd = Long.MAX_VALUE;
- for (int i = 0; i < alarms.size(); ) {
- Alarm alarm = alarms.get(i);
- if (UserHandle.getUserId(alarm.creatorUid) == userHandle) {
- alarms.remove(i);
- didRemove = true;
- if (alarm.alarmClock != null) {
- mNextAlarmClockMayChange = true;
- }
- } else {
- if (alarm.whenElapsed > newStart) {
- newStart = alarm.whenElapsed;
- }
- if (alarm.maxWhenElapsed < newEnd) {
- newEnd = alarm.maxWhenElapsed;
- }
- i++;
- }
- }
- if (didRemove) {
- // commit the new batch bounds
- start = newStart;
- end = newEnd;
- }
- return didRemove;
- }
-
boolean hasPackage(final String packageName) {
final int N = alarms.size();
for (int i = 0; i < N; i++) {
@@ -759,6 +648,8 @@
mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
mForceAppStandbyTracker.addListener(mForceAppStandbyListener);
+
+ publishLocalService(AlarmManagerInternal.class, new LocalService());
}
static long convertToElapsed(long when, int type) {
@@ -1554,6 +1445,21 @@
}
}
+ /**
+ * System-process internal API
+ */
+ private final class LocalService implements AlarmManagerInternal {
+ @Override
+ public void removeAlarmsForUid(int uid) {
+ synchronized (mLock) {
+ removeLocked(uid);
+ }
+ }
+ }
+
+ /**
+ * Public-facing binder interface
+ */
private final IBinder mService = new IAlarmManager.Stub() {
@Override
public void set(String callingPackage,
@@ -2430,10 +2336,19 @@
}
private void removeLocked(PendingIntent operation, IAlarmListener directReceiver) {
+ if (operation == null && directReceiver == null) {
+ if (localLOGV) {
+ Slog.w(TAG, "requested remove() of null operation",
+ new RuntimeException("here"));
+ }
+ return;
+ }
+
boolean didRemove = false;
+ final Predicate<Alarm> whichAlarms = (Alarm a) -> a.matches(operation, directReceiver);
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(operation, directReceiver);
+ didRemove |= b.remove(whichAlarms);
if (b.size() == 0) {
mAlarmBatches.remove(i);
}
@@ -2476,11 +2391,58 @@
}
}
- void removeLocked(String packageName) {
+ void removeLocked(final int uid) {
boolean didRemove = false;
+ final Predicate<Alarm> whichAlarms = (Alarm a) -> a.uid == uid;
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(packageName);
+ didRemove |= b.remove(whichAlarms);
+ if (b.size() == 0) {
+ mAlarmBatches.remove(i);
+ }
+ }
+ for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
+ final Alarm a = mPendingWhileIdleAlarms.get(i);
+ if (a.uid == uid) {
+ // Don't set didRemove, since this doesn't impact the scheduled alarms.
+ mPendingWhileIdleAlarms.remove(i);
+ }
+ }
+ for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i --) {
+ final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i);
+ for (int j = alarmsForUid.size() - 1; j >= 0; j--) {
+ if (alarmsForUid.get(j).uid == uid) {
+ alarmsForUid.remove(j);
+ }
+ }
+ if (alarmsForUid.size() == 0) {
+ mPendingBackgroundAlarms.removeAt(i);
+ }
+ }
+ if (didRemove) {
+ if (DEBUG_BATCH) {
+ Slog.v(TAG, "remove(uid) changed bounds; rebatching");
+ }
+ rebatchAllAlarmsLocked(true);
+ rescheduleKernelAlarmsLocked();
+ updateNextAlarmClockLocked();
+ }
+ }
+
+ void removeLocked(final String packageName) {
+ if (packageName == null) {
+ if (localLOGV) {
+ Slog.w(TAG, "requested remove() of null packageName",
+ new RuntimeException("here"));
+ }
+ return;
+ }
+
+ boolean didRemove = false;
+ final Predicate<Alarm> whichAlarms = (Alarm a) -> a.matches(packageName);
+ for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+ Batch b = mAlarmBatches.get(i);
+ didRemove |= b.remove(whichAlarms);
if (b.size() == 0) {
mAlarmBatches.remove(i);
}
@@ -2513,11 +2475,20 @@
}
}
- void removeForStoppedLocked(int uid) {
+ void removeForStoppedLocked(final int uid) {
boolean didRemove = false;
+ final Predicate<Alarm> whichAlarms = (Alarm a) -> {
+ try {
+ if (a.uid == uid && ActivityManager.getService().isAppStartModeDisabled(
+ uid, a.packageName)) {
+ return true;
+ }
+ } catch (RemoteException e) { /* fall through */}
+ return false;
+ };
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
Batch b = mAlarmBatches.get(i);
- didRemove |= b.removeForStopped(uid);
+ didRemove |= b.remove(whichAlarms);
if (b.size() == 0) {
mAlarmBatches.remove(i);
}
@@ -2546,9 +2517,11 @@
void removeUserLocked(int userHandle) {
boolean didRemove = false;
+ final Predicate<Alarm> whichAlarms =
+ (Alarm a) -> UserHandle.getUserId(a.creatorUid) == userHandle;
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(userHandle);
+ didRemove |= b.remove(whichAlarms);
if (b.size() == 0) {
mAlarmBatches.remove(i);
}
@@ -2967,7 +2940,7 @@
proto.write(AlarmProto.TAG, statsTag);
proto.write(AlarmProto.TYPE, type);
- proto.write(AlarmProto.WHEN_ELAPSED_MS, whenElapsed - nowElapsed);
+ proto.write(AlarmProto.TIME_UNTIL_WHEN_ELAPSED_MS, whenElapsed - nowElapsed);
proto.write(AlarmProto.WINDOW_LENGTH_MS, windowLength);
proto.write(AlarmProto.REPEAT_INTERVAL_MS, repeatInterval);
proto.write(AlarmProto.COUNT, count);
@@ -3396,6 +3369,7 @@
@Override
public void onReceive(Context context, Intent intent) {
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
synchronized (mLock) {
String action = intent.getAction();
String pkgList[] = null;
@@ -3416,7 +3390,6 @@
removeUserLocked(userHandle);
}
} else if (Intent.ACTION_UID_REMOVED.equals(action)) {
- int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
if (uid >= 0) {
mLastAllowWhileIdleDispatch.delete(uid);
}
@@ -3436,7 +3409,13 @@
}
if (pkgList != null && (pkgList.length > 0)) {
for (String pkg : pkgList) {
- removeLocked(pkg);
+ if (uid >= 0) {
+ // package-removed case
+ removeLocked(uid);
+ } else {
+ // external-applications-unavailable etc case
+ removeLocked(pkg);
+ }
mPriorities.remove(pkg);
for (int i=mBroadcastStats.size()-1; i>=0; i--) {
ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i);
diff --git a/services/core/java/com/android/server/AnimationThread.java b/services/core/java/com/android/server/AnimationThread.java
index 08392b0..c86042b 100644
--- a/services/core/java/com/android/server/AnimationThread.java
+++ b/services/core/java/com/android/server/AnimationThread.java
@@ -22,8 +22,8 @@
import android.os.Trace;
/**
- * Thread for handling all window animations, or anything that's directly impacting animations like
- * starting windows or traversals.
+ * Thread for handling all legacy window animations, or anything that's directly impacting
+ * animations like starting windows or traversals.
*/
public final class AnimationThread extends ServiceThread {
private static AnimationThread sInstance;
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index c34c30c..d9713a5 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 d7aeb8c..6f697c4 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;
@@ -1754,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.
@@ -1819,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);
@@ -1840,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) {
@@ -1862,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());
@@ -2699,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 {
@@ -2773,7 +2828,7 @@
becomeInactiveIfAppropriateLocked();
int curLightState = mLightState;
while (curLightState != LIGHT_STATE_IDLE) {
- stepIdleStateLocked("s:shell");
+ stepLightIdleStateLocked("s:shell");
if (curLightState == mLightState) {
pw.print("Unable to go light idle; stopped at ");
pw.println(lightStateToString(mLightState));
@@ -2985,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)) {
@@ -3001,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/GraphicsStatsService.java b/services/core/java/com/android/server/GraphicsStatsService.java
index d3f77b6..4639d75 100644
--- a/services/core/java/com/android/server/GraphicsStatsService.java
+++ b/services/core/java/com/android/server/GraphicsStatsService.java
@@ -175,7 +175,8 @@
0,
UserHandle.getUserId(uid));
synchronized (mLock) {
- pfd = requestBufferForProcessLocked(token, uid, pid, packageName, info.versionCode);
+ pfd = requestBufferForProcessLocked(token, uid, pid, packageName,
+ info.getLongVersionCode());
}
} catch (PackageManager.NameNotFoundException ex) {
throw new RemoteException("Unable to find package: '" + packageName + "'");
@@ -197,7 +198,7 @@
}
private ParcelFileDescriptor requestBufferForProcessLocked(IGraphicsStatsCallback token,
- int uid, int pid, String packageName, int versionCode) throws RemoteException {
+ int uid, int pid, String packageName, long versionCode) throws RemoteException {
ActiveBuffer buffer = fetchActiveBuffersLocked(token, uid, pid, packageName, versionCode);
scheduleRotateLocked();
return getPfd(buffer.mProcessBuffer);
@@ -292,7 +293,7 @@
}
private ActiveBuffer fetchActiveBuffersLocked(IGraphicsStatsCallback token, int uid, int pid,
- String packageName, int versionCode) throws RemoteException {
+ String packageName, long versionCode) throws RemoteException {
int size = mActive.size();
long today = normalizeDate(System.currentTimeMillis()).getTimeInMillis();
for (int i = 0; i < size; i++) {
@@ -381,19 +382,19 @@
private static native int nGetAshmemSize();
private static native long nCreateDump(int outFd, boolean isProto);
private static native void nAddToDump(long dump, String path, String packageName,
- int versionCode, long startTime, long endTime, byte[] data);
+ long versionCode, long startTime, long endTime, byte[] data);
private static native void nAddToDump(long dump, String path);
private static native void nFinishDump(long dump);
- private static native void nSaveBuffer(String path, String packageName, int versionCode,
+ private static native void nSaveBuffer(String path, String packageName, long versionCode,
long startTime, long endTime, byte[] data);
private final class BufferInfo {
final String packageName;
- final int versionCode;
+ final long versionCode;
long startTime;
long endTime;
- BufferInfo(String packageName, int versionCode, long startTime) {
+ BufferInfo(String packageName, long versionCode, long startTime) {
this.packageName = packageName;
this.versionCode = versionCode;
this.startTime = startTime;
@@ -408,7 +409,8 @@
final IBinder mToken;
MemoryFile mProcessBuffer;
- ActiveBuffer(IGraphicsStatsCallback token, int uid, int pid, String packageName, int versionCode)
+ ActiveBuffer(IGraphicsStatsCallback token, int uid, int pid, String packageName,
+ long versionCode)
throws RemoteException, IOException {
mInfo = new BufferInfo(packageName, versionCode, System.currentTimeMillis());
mUid = uid;
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index fc57a0d..25c3fe4 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -49,12 +49,14 @@
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import android.Manifest;
import android.annotation.BinderThread;
import android.annotation.ColorInt;
import android.annotation.IntDef;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -91,6 +93,7 @@
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.Environment;
@@ -104,10 +107,14 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
import android.os.SystemClock;
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;
@@ -176,6 +183,13 @@
static final boolean DEBUG_RESTORE = DEBUG || false;
static final String TAG = "InputMethodManagerService";
+ @Retention(SOURCE)
+ @IntDef({ShellCommandResult.SUCCESS, ShellCommandResult.FAILURE})
+ private @interface ShellCommandResult {
+ int SUCCESS = 0;
+ int FAILURE = -1;
+ }
+
static final int MSG_SHOW_IM_SUBTYPE_PICKER = 1;
static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 2;
static final int MSG_SHOW_IM_CONFIG = 3;
@@ -189,6 +203,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 +332,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 +900,30 @@
}
/**
+ * Start a VR InputMethod that matches IME with package name of {@param component}.
+ * Note: This method is called from {@link android.app.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.
+ setInputMethodEnabledLocked(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 +1399,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 +1632,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;
}
}
@@ -2639,10 +2724,12 @@
/* @InputMethodClient.StartInputReason */ final int startInputReason,
IInputMethodClient client, IBinder windowToken, int controlFlags, int softInputMode,
int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
- /* @InputConnectionInspector.missingMethods */ final int missingMethods) {
+ /* @InputConnectionInspector.missingMethods */ final int missingMethods,
+ int unverifiedTargetSdkVersion) {
if (windowToken != null) {
return windowGainedFocus(startInputReason, client, windowToken, controlFlags,
- softInputMode, windowFlags, attribute, inputContext, missingMethods);
+ softInputMode, windowFlags, attribute, inputContext, missingMethods,
+ unverifiedTargetSdkVersion);
} else {
return startInput(startInputReason, client, inputContext, missingMethods, attribute,
controlFlags);
@@ -2654,7 +2741,8 @@
IInputMethodClient client, IBinder windowToken, int controlFlags,
/* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
int windowFlags, EditorInfo attribute, IInputContext inputContext,
- /* @InputConnectionInspector.missingMethods */ final int missingMethods) {
+ /* @InputConnectionInspector.missingMethods */ final int missingMethods,
+ int unverifiedTargetSdkVersion) {
// Needs to check the validity before clearing calling identity
final boolean calledFromValidUser = calledFromValidUser();
InputBindResult res = null;
@@ -2670,7 +2758,8 @@
+ " attribute=" + attribute
+ " controlFlags=#" + Integer.toHexString(controlFlags)
+ " softInputMode=" + InputMethodClient.softInputModeToString(softInputMode)
- + " windowFlags=#" + Integer.toHexString(windowFlags));
+ + " windowFlags=#" + Integer.toHexString(windowFlags)
+ + " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion);
ClientState cs = mClients.get(client.asBinder());
if (cs == null) {
@@ -2784,22 +2873,37 @@
if ((softInputMode &
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
- if (attribute != null) {
- res = startInputUncheckedLocked(cs, inputContext,
- missingMethods, attribute, controlFlags, startInputReason);
- didStart = true;
+ if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
+ unverifiedTargetSdkVersion, controlFlags)) {
+ if (attribute != null) {
+ res = startInputUncheckedLocked(cs, inputContext,
+ missingMethods, attribute, controlFlags,
+ startInputReason);
+ didStart = true;
+ }
+ showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
+ } else {
+ Slog.e(TAG, "SOFT_INPUT_STATE_VISIBLE is ignored because"
+ + " there is no focused view that also returns true from"
+ + " View#onCheckIsTextEditor()");
}
- showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
}
break;
case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
if (DEBUG) Slog.v(TAG, "Window asks to always show input");
- if (attribute != null) {
- res = startInputUncheckedLocked(cs, inputContext, missingMethods,
- attribute, controlFlags, startInputReason);
- didStart = true;
+ if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
+ unverifiedTargetSdkVersion, controlFlags)) {
+ if (attribute != null) {
+ res = startInputUncheckedLocked(cs, inputContext, missingMethods,
+ attribute, controlFlags, startInputReason);
+ didStart = true;
+ }
+ showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
+ } else {
+ Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
+ + " there is no focused view that also returns true from"
+ + " View#onCheckIsTextEditor()");
}
- showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
break;
}
@@ -3356,6 +3460,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;
@@ -3809,30 +3916,6 @@
// ----------------------------------------------------------------------
- @Override
- public boolean setInputMethodEnabled(String id, boolean enabled) {
- // TODO: Make this work even for non-current users?
- if (!calledFromValidUser()) {
- return false;
- }
- synchronized (mMethodMap) {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- "Requires permission "
- + android.Manifest.permission.WRITE_SECURE_SETTINGS);
- }
-
- long ident = Binder.clearCallingIdentity();
- try {
- return setInputMethodEnabledLocked(id, enabled);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
-
boolean setInputMethodEnabledLocked(String id, boolean enabled) {
// Make sure this is a valid input method.
InputMethodInfo imm = mMethodMap.get(id);
@@ -3876,8 +3959,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 +3979,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 +4443,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) {
@@ -4543,4 +4640,257 @@
p.println("No input method service.");
}
}
+
+ @BinderThread
+ @Override
+ public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+ @Nullable FileDescriptor err,
+ @NonNull String[] args, @Nullable ShellCallback callback,
+ @NonNull ResultReceiver resultReceiver) throws RemoteException {
+ new ShellCommandImpl(this).exec(
+ this, in, out, err, args, callback, resultReceiver);
+ }
+
+ private static final class ShellCommandImpl extends ShellCommand {
+ @NonNull
+ final InputMethodManagerService mService;
+
+ ShellCommandImpl(InputMethodManagerService service) {
+ mService = service;
+ }
+
+ @BinderThread
+ @ShellCommandResult
+ @Override
+ public int onCommand(@Nullable String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ switch (cmd) {
+ case "list":
+ return mService.handleShellCommandListInputMethods(this);
+ case "enable":
+ return mService.handleShellCommandEnableDisableInputMethod(this, true);
+ case "disable":
+ return mService.handleShellCommandEnableDisableInputMethod(this, false);
+ case "set":
+ return mService.handleShellCommandSetInputMethod(this);
+ case "reset-ime":
+ return mService.handleShellCommandResetInputMethod(this);
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ }
+
+ @BinderThread
+ @Override
+ public void onHelp() {
+ try (PrintWriter pw = getOutPrintWriter()) {
+ pw.println("InputMethodManagerService commands:");
+ pw.println(" help");
+ pw.println(" Prints this help text.");
+ pw.println(" dump [options]");
+ pw.println(" Synonym of dumpsys.");
+ pw.println(" list [-a] [-s]");
+ pw.println(" prints all enabled input methods.");
+ pw.println(" -a: see all input methods");
+ pw.println(" -s: only a single summary line of each");
+ pw.println(" enable <ID>");
+ pw.println(" allows the given input method ID to be used.");
+ pw.println(" disable <ID>");
+ pw.println(" disallows the given input method ID to be used.");
+ pw.println(" set <ID>");
+ pw.println(" switches to the given input method ID.");
+ pw.println(" reset-ime");
+ pw.println(" reset currently selected/enabled IMEs to the default ones as if");
+ pw.println(" the device is initially booted with the current locale.");
+ }
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ // Shell command handlers:
+
+ /**
+ * Handles {@code adb shell ime list}.
+ * @param shellCommand {@link ShellCommand} object that is handling this command.
+ * @return Exit code of the command.
+ */
+ @BinderThread
+ @ShellCommandResult
+ private int handleShellCommandListInputMethods(@NonNull ShellCommand shellCommand) {
+ boolean all = false;
+ boolean brief = false;
+ while (true) {
+ final String nextOption = shellCommand.getNextOption();
+ if (nextOption == null) {
+ break;
+ }
+ switch (nextOption) {
+ case "-a":
+ all = true;
+ break;
+ case "-s":
+ brief = true;
+ break;
+ }
+ }
+ final List<InputMethodInfo> methods = all ?
+ getInputMethodList() : getEnabledInputMethodList();
+ final PrintWriter pr = shellCommand.getOutPrintWriter();
+ final Printer printer = x -> pr.println(x);
+ final int N = methods.size();
+ for (int i = 0; i < N; ++i) {
+ if (brief) {
+ pr.println(methods.get(i).getId());
+ } else {
+ pr.print(methods.get(i).getId()); pr.println(":");
+ methods.get(i).dump(printer, " ");
+ }
+ }
+ return ShellCommandResult.SUCCESS;
+ }
+
+ /**
+ * Handles {@code adb shell ime enable} and {@code adb shell ime disable}.
+ * @param shellCommand {@link ShellCommand} object that is handling this command.
+ * @param enabled {@code true} if the command was {@code adb shell ime enable}.
+ * @return Exit code of the command.
+ */
+ @BinderThread
+ @ShellCommandResult
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ private int handleShellCommandEnableDisableInputMethod(
+ @NonNull ShellCommand shellCommand, boolean enabled) {
+ if (!calledFromValidUser()) {
+ shellCommand.getErrPrintWriter().print(
+ "Must be called from the foreground user or with INTERACT_ACROSS_USERS_FULL");
+ return ShellCommandResult.FAILURE;
+ }
+ final String id = shellCommand.getNextArgRequired();
+
+ final boolean previouslyEnabled;
+ synchronized (mMethodMap) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ shellCommand.getErrPrintWriter().print(
+ "Caller must have WRITE_SECURE_SETTINGS permission");
+ throw new SecurityException(
+ "Requires permission "
+ + android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ previouslyEnabled = setInputMethodEnabledLocked(id, enabled);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ final PrintWriter pr = shellCommand.getOutPrintWriter();
+ pr.print("Input method ");
+ pr.print(id);
+ pr.print(": ");
+ pr.print((enabled == previouslyEnabled) ? "already " : "now ");
+ pr.println(enabled ? "enabled" : "disabled");
+ return ShellCommandResult.SUCCESS;
+ }
+
+ /**
+ * Handles {@code adb shell ime set}.
+ * @param shellCommand {@link ShellCommand} object that is handling this command.
+ * @return Exit code of the command.
+ */
+ @BinderThread
+ @ShellCommandResult
+ private int handleShellCommandSetInputMethod(@NonNull ShellCommand shellCommand) {
+ final String id = shellCommand.getNextArgRequired();
+ setInputMethod(null, id);
+ final PrintWriter pr = shellCommand.getOutPrintWriter();
+ pr.print("Input method ");
+ pr.print(id);
+ pr.println(" selected");
+ return ShellCommandResult.SUCCESS;
+ }
+
+ /**
+ * Handles {@code adb shell ime reset-ime}.
+ * @param shellCommand {@link ShellCommand} object that is handling this command.
+ * @return Exit code of the command.
+ */
+ @BinderThread
+ @ShellCommandResult
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
+ if (!calledFromValidUser()) {
+ shellCommand.getErrPrintWriter().print(
+ "Must be called from the foreground user or with INTERACT_ACROSS_USERS_FULL");
+ return ShellCommandResult.FAILURE;
+ }
+ synchronized (mMethodMap) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ shellCommand.getErrPrintWriter().print(
+ "Caller must have WRITE_SECURE_SETTINGS permission");
+ throw new SecurityException(
+ "Requires permission "
+ + android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ }
+ final String nextIme;
+ final List<InputMethodInfo> nextEnabledImes;
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mMethodMap) {
+ hideCurrentInputLocked(0, null);
+ unbindCurrentMethodLocked(false);
+ // Reset the current IME
+ resetSelectedInputMethodAndSubtypeLocked(null);
+ // Also reset the settings of the current IME
+ mSettings.putSelectedInputMethod(null);
+ // Disable all enabled IMEs.
+ {
+ final ArrayList<InputMethodInfo> enabledImes =
+ mSettings.getEnabledInputMethodListLocked();
+ final int N = enabledImes.size();
+ for (int i = 0; i < N; ++i) {
+ setInputMethodEnabledLocked(enabledImes.get(i).getId(), false);
+ }
+ }
+ // Re-enable with default enabled IMEs.
+ {
+ final ArrayList<InputMethodInfo> defaultEnabledIme =
+ InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList);
+ final int N = defaultEnabledIme.size();
+ for (int i = 0; i < N; ++i) {
+ setInputMethodEnabledLocked(defaultEnabledIme.get(i).getId(), true);
+ }
+ }
+ updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
+ InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
+ mSettings.getEnabledInputMethodListLocked(),
+ mSettings.getCurrentUserId(),
+ mContext.getBasePackageName());
+ nextIme = mSettings.getSelectedInputMethod();
+ nextEnabledImes = getEnabledInputMethodList();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ final PrintWriter pr = shellCommand.getOutPrintWriter();
+ pr.println("Reset current and enabled IMEs");
+ pr.println("Newly selected IME:");
+ pr.print(" "); pr.println(nextIme);
+ pr.println("Newly enabled IMEs:");
+ {
+ final int N = nextEnabledImes.size();
+ for (int i = 0; i < N; ++i) {
+ pr.print(" ");
+ pr.println(nextEnabledImes.get(i).getId());
+ }
+ }
+ return ShellCommandResult.SUCCESS;
+ }
+ }
}
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/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 1154fbe..2116d9a 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -57,11 +57,23 @@
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import libcore.io.IoUtils;
-/** @hide */
+/**
+ * A service to manage multiple clients that want to access the IpSec API. The service is
+ * responsible for maintaining a list of clients and managing the resources (and related quotas)
+ * that each of them own.
+ *
+ * <p>Synchronization in IpSecService is done on all entrypoints due to potential race conditions at
+ * the kernel/xfrm level. Further, this allows the simplifying assumption to be made that only one
+ * thread is ever running at a time.
+ *
+ * @hide
+ */
public class IpSecService extends IIpSecService.Stub {
private static final String TAG = "IpSecService";
private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
@@ -91,17 +103,6 @@
/** Should be a never-repeating global ID for resources */
private static AtomicInteger mNextResourceId = new AtomicInteger(0x00FADED0);
- @GuardedBy("this")
- private final ManagedResourceArray<SpiRecord> mSpiRecords = new ManagedResourceArray<>();
-
- @GuardedBy("this")
- private final ManagedResourceArray<TransformRecord> mTransformRecords =
- new ManagedResourceArray<>();
-
- @GuardedBy("this")
- private final ManagedResourceArray<UdpSocketRecord> mUdpSocketRecords =
- new ManagedResourceArray<>();
-
interface IpSecServiceConfiguration {
INetd getNetdInstance() throws RemoteException;
@@ -120,8 +121,176 @@
private final IpSecServiceConfiguration mSrvConfig;
+ /**
+ * Interface for user-reference and kernel-resource cleanup.
+ *
+ * <p>This interface must be implemented for a resource to be reference counted.
+ */
+ @VisibleForTesting
+ public interface IResource {
+ /**
+ * Invalidates a IResource object, ensuring it is invalid for the purposes of allocating new
+ * objects dependent on it.
+ *
+ * <p>Implementations of this method are expected to remove references to the IResource
+ * object from the IpSecService's tracking arrays. The removal from the arrays ensures that
+ * the resource is considered invalid for user access or allocation or use in other
+ * resources.
+ *
+ * <p>References to the IResource object may be held by other RefcountedResource objects,
+ * and as such, the kernel resources and quota may not be cleaned up.
+ */
+ void invalidate() throws RemoteException;
+
+ /**
+ * Releases underlying resources and related quotas.
+ *
+ * <p>Implementations of this method are expected to remove all system resources that are
+ * tracked by the IResource object. Due to other RefcountedResource objects potentially
+ * having references to the IResource object, freeUnderlyingResources may not always be
+ * called from releaseIfUnreferencedRecursively().
+ */
+ void freeUnderlyingResources() throws RemoteException;
+ }
+
+ /**
+ * RefcountedResource manages references and dependencies in an exclusively acyclic graph.
+ *
+ * <p>RefcountedResource implements both explicit and implicit resource management. Creating a
+ * RefcountedResource object creates an explicit reference that must be freed by calling
+ * userRelease(). Additionally, adding this object as a child of another RefcountedResource
+ * object will add an implicit reference.
+ *
+ * <p>Resources are cleaned up when all references, both implicit and explicit, are released
+ * (ie, when userRelease() is called and when all parents have called releaseReference() on this
+ * object.)
+ */
+ @VisibleForTesting
+ public class RefcountedResource<T extends IResource> implements IBinder.DeathRecipient {
+ private final T mResource;
+ private final List<RefcountedResource> mChildren;
+ int mRefCount = 1; // starts at 1 for user's reference.
+ IBinder mBinder;
+
+ RefcountedResource(T resource, IBinder binder, RefcountedResource... children) {
+ synchronized (IpSecService.this) {
+ this.mResource = resource;
+ this.mChildren = new ArrayList<>(children.length);
+ this.mBinder = binder;
+
+ for (RefcountedResource child : children) {
+ mChildren.add(child);
+ child.mRefCount++;
+ }
+
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ binderDied();
+ }
+ }
+ }
+
+ /**
+ * If the Binder object dies, this function is called to free the system resources that are
+ * being tracked by this record and to subsequently release this record for garbage
+ * collection
+ */
+ @Override
+ public void binderDied() {
+ synchronized (IpSecService.this) {
+ try {
+ userRelease();
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to release resource: " + e);
+ }
+ }
+ }
+
+ public T getResource() {
+ return mResource;
+ }
+
+ /**
+ * Unlinks from binder and performs IpSecService resource cleanup (removes from resource
+ * arrays)
+ *
+ * <p>If this method has been previously called, the RefcountedResource's binder field will
+ * be null, and the method will return without performing the cleanup a second time.
+ *
+ * <p>Note that calling this function does not imply that kernel resources will be freed at
+ * this time, or that the related quota will be returned. Such actions will only be
+ * performed upon the reference count reaching zero.
+ */
+ @GuardedBy("IpSecService.this")
+ public void userRelease() throws RemoteException {
+ // Prevent users from putting reference counts into a bad state by calling
+ // userRelease() multiple times.
+ if (mBinder == null) {
+ return;
+ }
+
+ mBinder.unlinkToDeath(this, 0);
+ mBinder = null;
+
+ mResource.invalidate();
+
+ releaseReference();
+ }
+
+ /**
+ * Removes a reference to this resource. If the resultant reference count is zero, the
+ * underlying resources are freed, and references to all child resources are also dropped
+ * recursively (resulting in them freeing their resources and children, etcetera)
+ *
+ * <p>This method also sets the reference count to an invalid value (-1) to signify that it
+ * has been fully released. Any subsequent calls to this method will result in an
+ * IllegalStateException being thrown due to resource already having been previously
+ * released
+ */
+ @VisibleForTesting
+ @GuardedBy("IpSecService.this")
+ public void releaseReference() throws RemoteException {
+ mRefCount--;
+
+ if (mRefCount > 0) {
+ return;
+ } else if (mRefCount < 0) {
+ throw new IllegalStateException(
+ "Invalid operation - resource has already been released.");
+ }
+
+ // Cleanup own resources
+ mResource.freeUnderlyingResources();
+
+ // Cleanup child resources as needed
+ for (RefcountedResource<? extends IResource> child : mChildren) {
+ child.releaseReference();
+ }
+
+ // Enforce that resource cleanup can only be called once
+ // By decrementing the refcount (from 0 to -1), the next call will throw an
+ // IllegalStateException - it has already been released fully.
+ mRefCount--;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append("{mResource=")
+ .append(mResource)
+ .append(", mRefCount=")
+ .append(mRefCount)
+ .append(", mChildren=")
+ .append(mChildren)
+ .append("}")
+ .toString();
+ }
+ }
+
/* Very simple counting class that looks much like a counting semaphore */
- public static class ResourceTracker {
+ @VisibleForTesting
+ static class ResourceTracker {
private final int mMax;
int mCurrent;
@@ -130,18 +299,18 @@
mCurrent = 0;
}
- synchronized boolean isAvailable() {
+ boolean isAvailable() {
return (mCurrent < mMax);
}
- synchronized void take() {
+ void take() {
if (!isAvailable()) {
Log.wtf(TAG, "Too many resources allocated!");
}
mCurrent++;
}
- synchronized void give() {
+ void give() {
if (mCurrent <= 0) {
Log.wtf(TAG, "We've released this resource too many times");
}
@@ -160,40 +329,70 @@
}
}
- private static final class UserQuotaTracker {
- /* Maximum number of UDP Encap Sockets that a single UID may possess */
+ @VisibleForTesting
+ static final class UserRecord {
+ /* Type names */
+ public static final String TYPENAME_SPI = "SecurityParameterIndex";
+ public static final String TYPENAME_TRANSFORM = "IpSecTransform";
+ public static final String TYPENAME_ENCAP_SOCKET = "UdpEncapSocket";
+
+ /* Maximum number of each type of resource that a single UID may possess */
public static final int MAX_NUM_ENCAP_SOCKETS = 2;
-
- /* Maximum number of IPsec Transforms that a single UID may possess */
public static final int MAX_NUM_TRANSFORMS = 4;
-
- /* Maximum number of IPsec Transforms that a single UID may possess */
public static final int MAX_NUM_SPIS = 8;
- /* Record for one users's IpSecService-managed objects */
- public static class UserRecord {
- public final ResourceTracker socket = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS);
- public final ResourceTracker transform = new ResourceTracker(MAX_NUM_TRANSFORMS);
- public final ResourceTracker spi = new ResourceTracker(MAX_NUM_SPIS);
+ final RefcountedResourceArray<SpiRecord> mSpiRecords =
+ new RefcountedResourceArray<>(TYPENAME_SPI);
+ final ResourceTracker mSpiQuotaTracker = new ResourceTracker(MAX_NUM_SPIS);
- @Override
- public String toString() {
- return new StringBuilder()
- .append("{socket=")
- .append(socket)
- .append(", transform=")
- .append(transform)
- .append(", spi=")
- .append(spi)
- .append("}")
- .toString();
- }
+ final RefcountedResourceArray<TransformRecord> mTransformRecords =
+ new RefcountedResourceArray<>(TYPENAME_TRANSFORM);
+ final ResourceTracker mTransformQuotaTracker = new ResourceTracker(MAX_NUM_TRANSFORMS);
+
+ final RefcountedResourceArray<EncapSocketRecord> mEncapSocketRecords =
+ new RefcountedResourceArray<>(TYPENAME_ENCAP_SOCKET);
+ final ResourceTracker mSocketQuotaTracker = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS);
+
+ void removeSpiRecord(int resourceId) {
+ mSpiRecords.remove(resourceId);
}
+ void removeTransformRecord(int resourceId) {
+ mTransformRecords.remove(resourceId);
+ }
+
+ void removeEncapSocketRecord(int resourceId) {
+ mEncapSocketRecords.remove(resourceId);
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append("{mSpiQuotaTracker=")
+ .append(mSpiQuotaTracker)
+ .append(", mTransformQuotaTracker=")
+ .append(mTransformQuotaTracker)
+ .append(", mSocketQuotaTracker=")
+ .append(mSocketQuotaTracker)
+ .append(", mSpiRecords=")
+ .append(mSpiRecords)
+ .append(", mTransformRecords=")
+ .append(mTransformRecords)
+ .append(", mEncapSocketRecords=")
+ .append(mEncapSocketRecords)
+ .append("}")
+ .toString();
+ }
+ }
+
+ @VisibleForTesting
+ static final class UserResourceTracker {
private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
- /* a never-fail getter so that we can populate the list of UIDs as-needed */
- public synchronized UserRecord getUserRecord(int uid) {
+ /** Never-fail getter that populates the list of UIDs as-needed */
+ public UserRecord getUserRecord(int uid) {
+ checkCallerUid(uid);
+
UserRecord r = mUserRecords.get(uid);
if (r == null) {
r = new UserRecord();
@@ -202,122 +401,56 @@
return r;
}
+ /** Safety method; guards against access of other user's UserRecords */
+ private void checkCallerUid(int uid) {
+ if (uid != Binder.getCallingUid()
+ && android.os.Process.SYSTEM_UID != Binder.getCallingUid()) {
+ throw new SecurityException("Attempted access of unowned resources");
+ }
+ }
+
@Override
public String toString() {
return mUserRecords.toString();
}
}
- private final UserQuotaTracker mUserQuotaTracker = new UserQuotaTracker();
+ @VisibleForTesting final UserResourceTracker mUserResourceTracker = new UserResourceTracker();
/**
- * The ManagedResource class provides a facility to cleanly and reliably release system
- * resources. It relies on two things: an IBinder that allows ManagedResource to automatically
- * clean up in the event that the Binder dies and a user-provided resourceId that should
- * uniquely identify the managed resource. To use this class, the user should implement the
- * releaseResources() method that is responsible for releasing system resources when invoked.
+ * The KernelResourceRecord class provides a facility to cleanly and reliably track system
+ * resources. It relies on a provided resourceId that should uniquely identify the kernel
+ * resource. To use this class, the user should implement the invalidate() and
+ * freeUnderlyingResources() methods that are responsible for cleaning up IpSecService resource
+ * tracking arrays and kernel resources, respectively
*/
- private abstract class ManagedResource implements IBinder.DeathRecipient {
+ private abstract class KernelResourceRecord implements IResource {
final int pid;
final int uid;
- private IBinder mBinder;
- protected int mResourceId;
+ protected final int mResourceId;
- private AtomicInteger mReferenceCount = new AtomicInteger(0);
-
- ManagedResource(int resourceId, IBinder binder) {
+ KernelResourceRecord(int resourceId) {
super();
if (resourceId == INVALID_RESOURCE_ID) {
throw new IllegalArgumentException("Resource ID must not be INVALID_RESOURCE_ID");
}
- mBinder = binder;
mResourceId = resourceId;
pid = Binder.getCallingPid();
uid = Binder.getCallingUid();
getResourceTracker().take();
- try {
- mBinder.linkToDeath(this, 0);
- } catch (RemoteException e) {
- binderDied();
- }
}
- public void addReference() {
- mReferenceCount.incrementAndGet();
+ @Override
+ public abstract void invalidate() throws RemoteException;
+
+ /** Convenience method; retrieves the user resource record for the stored UID. */
+ protected UserRecord getUserRecord() {
+ return mUserResourceTracker.getUserRecord(uid);
}
- public void removeReference() {
- if (mReferenceCount.decrementAndGet() < 0) {
- Log.wtf(TAG, "Programming error: negative reference count");
- }
- }
-
- public boolean isReferenced() {
- return (mReferenceCount.get() > 0);
- }
-
- /**
- * Ensures that the caller is either the owner of this resource or has the system UID and
- * throws a SecurityException otherwise.
- */
- public void checkOwnerOrSystem() {
- if (uid != Binder.getCallingUid()
- && android.os.Process.SYSTEM_UID != Binder.getCallingUid()) {
- throw new SecurityException("Only the owner may access managed resources!");
- }
- }
-
- /**
- * When this record is no longer needed for managing system resources this function should
- * clean up all system resources and nullify the record. This function shall perform all
- * necessary cleanup of the resources managed by this record.
- *
- * <p>NOTE: this function verifies ownership before allowing resources to be freed.
- */
- public final void release() throws RemoteException {
- synchronized (IpSecService.this) {
- if (isReferenced()) {
- throw new IllegalStateException(
- "Cannot release a resource that has active references!");
- }
-
- if (mResourceId == INVALID_RESOURCE_ID) {
- return;
- }
-
- releaseResources();
- getResourceTracker().give();
- if (mBinder != null) {
- mBinder.unlinkToDeath(this, 0);
- }
- mBinder = null;
-
- mResourceId = INVALID_RESOURCE_ID;
- }
- }
-
- /**
- * If the Binder object dies, this function is called to free the system resources that are
- * being managed by this record and to subsequently release this record for garbage
- * collection
- */
- public final void binderDied() {
- try {
- release();
- } catch (Exception e) {
- Log.e(TAG, "Failed to release resource: " + e);
- }
- }
-
- /**
- * Implement this method to release all system resources that are being protected by this
- * record. Once the resources are released, the record should be invalidated and no longer
- * used by calling release(). This should NEVER be called directly.
- *
- * <p>Calls to this are always guarded by IpSecService#this
- */
- protected abstract void releaseResources() throws RemoteException;
+ @Override
+ public abstract void freeUnderlyingResources() throws RemoteException;
/** Get the resource tracker for this resource */
protected abstract ResourceTracker getResourceTracker();
@@ -331,30 +464,52 @@
.append(pid)
.append(", uid=")
.append(uid)
- .append(", mReferenceCount=")
- .append(mReferenceCount.get())
.append("}")
.toString();
}
};
+ // TODO: Move this to right after RefcountedResource. With this here, Gerrit was showing many
+ // more things as changed.
/**
- * Minimal wrapper around SparseArray that performs ownership validation on element accesses.
+ * Thin wrapper over SparseArray to ensure resources exist, and simplify generic typing.
+ *
+ * <p>RefcountedResourceArray prevents null insertions, and throws an IllegalArgumentException
+ * if a key is not found during a retrieval process.
*/
- private class ManagedResourceArray<T extends ManagedResource> {
- SparseArray<T> mArray = new SparseArray<>();
+ static class RefcountedResourceArray<T extends IResource> {
+ SparseArray<RefcountedResource<T>> mArray = new SparseArray<>();
+ private final String mTypeName;
- T getAndCheckOwner(int key) {
- T val = mArray.get(key);
- // The value should never be null unless the resource doesn't exist
- // (since we do not allow null resources to be added).
- if (val != null) {
- val.checkOwnerOrSystem();
- }
- return val;
+ public RefcountedResourceArray(String typeName) {
+ this.mTypeName = typeName;
}
- void put(int key, T obj) {
+ /**
+ * Accessor method to get inner resource object.
+ *
+ * @throws IllegalArgumentException if no resource with provided key is found.
+ */
+ T getResourceOrThrow(int key) {
+ return getRefcountedResourceOrThrow(key).getResource();
+ }
+
+ /**
+ * Accessor method to get reference counting wrapper.
+ *
+ * @throws IllegalArgumentException if no resource with provided key is found.
+ */
+ RefcountedResource<T> getRefcountedResourceOrThrow(int key) {
+ RefcountedResource<T> resource = mArray.get(key);
+ if (resource == null) {
+ throw new IllegalArgumentException(
+ String.format("No such %s found for given id: %d", mTypeName, key));
+ }
+
+ return resource;
+ }
+
+ void put(int key, RefcountedResource<T> obj) {
checkNotNull(obj, "Null resources cannot be added");
mArray.put(key, obj);
}
@@ -369,30 +524,17 @@
}
}
- private final class TransformRecord extends ManagedResource {
+ private final class TransformRecord extends KernelResourceRecord {
private final IpSecConfig mConfig;
private final SpiRecord[] mSpis;
- private final UdpSocketRecord mSocket;
+ private final EncapSocketRecord mSocket;
TransformRecord(
- int resourceId,
- IBinder binder,
- IpSecConfig config,
- SpiRecord[] spis,
- UdpSocketRecord socket) {
- super(resourceId, binder);
+ int resourceId, IpSecConfig config, SpiRecord[] spis, EncapSocketRecord socket) {
+ super(resourceId);
mConfig = config;
mSpis = spis;
mSocket = socket;
-
- for (int direction : DIRECTIONS) {
- mSpis[direction].addReference();
- mSpis[direction].setOwnedByTransform();
- }
-
- if (mSocket != null) {
- mSocket.addReference();
- }
}
public IpSecConfig getConfig() {
@@ -405,7 +547,7 @@
/** always guarded by IpSecService#this */
@Override
- protected void releaseResources() {
+ public void freeUnderlyingResources() {
for (int direction : DIRECTIONS) {
int spi = mSpis[direction].getSpi();
try {
@@ -424,17 +566,17 @@
}
}
- for (int direction : DIRECTIONS) {
- mSpis[direction].removeReference();
- }
-
- if (mSocket != null) {
- mSocket.removeReference();
- }
+ getResourceTracker().give();
}
+ @Override
+ public void invalidate() throws RemoteException {
+ getUserRecord().removeTransformRecord(mResourceId);
+ }
+
+ @Override
protected ResourceTracker getResourceTracker() {
- return mUserQuotaTracker.getUserRecord(this.uid).transform;
+ return getUserRecord().mTransformQuotaTracker;
}
@Override
@@ -456,7 +598,7 @@
}
}
- private final class SpiRecord extends ManagedResource {
+ private final class SpiRecord extends KernelResourceRecord {
private final int mDirection;
private final String mLocalAddress;
private final String mRemoteAddress;
@@ -466,12 +608,11 @@
SpiRecord(
int resourceId,
- IBinder binder,
int direction,
String localAddress,
String remoteAddress,
int spi) {
- super(resourceId, binder);
+ super(resourceId);
mDirection = direction;
mLocalAddress = localAddress;
mRemoteAddress = remoteAddress;
@@ -480,7 +621,7 @@
/** always guarded by IpSecService#this */
@Override
- protected void releaseResources() {
+ public void freeUnderlyingResources() {
if (mOwnedByTransform) {
Log.d(TAG, "Cannot release Spi " + mSpi + ": Currently locked by a Transform");
// Because SPIs are "handed off" to transform, objects, they should never be
@@ -503,11 +644,8 @@
}
mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
- }
- @Override
- protected ResourceTracker getResourceTracker() {
- return mUserQuotaTracker.getUserRecord(this.uid).spi;
+ getResourceTracker().give();
}
public int getSpi() {
@@ -524,6 +662,16 @@
}
@Override
+ public void invalidate() throws RemoteException {
+ getUserRecord().removeSpiRecord(mResourceId);
+ }
+
+ @Override
+ protected ResourceTracker getResourceTracker() {
+ return getUserRecord().mSpiQuotaTracker;
+ }
+
+ @Override
public String toString() {
StringBuilder strBuilder = new StringBuilder();
strBuilder
@@ -544,27 +692,24 @@
}
}
- private final class UdpSocketRecord extends ManagedResource {
+ private final class EncapSocketRecord extends KernelResourceRecord {
private FileDescriptor mSocket;
private final int mPort;
- UdpSocketRecord(int resourceId, IBinder binder, FileDescriptor socket, int port) {
- super(resourceId, binder);
+ EncapSocketRecord(int resourceId, FileDescriptor socket, int port) {
+ super(resourceId);
mSocket = socket;
mPort = port;
}
/** always guarded by IpSecService#this */
@Override
- protected void releaseResources() {
+ public void freeUnderlyingResources() {
Log.d(TAG, "Closing port " + mPort);
IoUtils.closeQuietly(mSocket);
mSocket = null;
- }
- @Override
- protected ResourceTracker getResourceTracker() {
- return mUserQuotaTracker.getUserRecord(this.uid).socket;
+ getResourceTracker().give();
}
public int getPort() {
@@ -576,6 +721,16 @@
}
@Override
+ protected ResourceTracker getResourceTracker() {
+ return getUserRecord().mSocketQuotaTracker;
+ }
+
+ @Override
+ public void invalidate() {
+ getUserRecord().removeEncapSocketRecord(mResourceId);
+ }
+
+ @Override
public String toString() {
return new StringBuilder()
.append("{super=")
@@ -682,13 +837,14 @@
/* requestedSpi can be anything in the int range, so no check is needed. */
checkNotNull(binder, "Null Binder passed to reserveSecurityParameterIndex");
+ UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
int resourceId = mNextResourceId.getAndIncrement();
int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
String localAddress = "";
try {
- if (!mUserQuotaTracker.getUserRecord(Binder.getCallingUid()).spi.isAvailable()) {
+ if (!userRecord.mSpiQuotaTracker.isAvailable()) {
return new IpSecSpiResponse(
IpSecManager.Status.RESOURCE_UNAVAILABLE, INVALID_RESOURCE_ID, spi);
}
@@ -702,9 +858,11 @@
remoteAddress,
requestedSpi);
Log.d(TAG, "Allocated SPI " + spi);
- mSpiRecords.put(
+ userRecord.mSpiRecords.put(
resourceId,
- new SpiRecord(resourceId, binder, direction, localAddress, remoteAddress, spi));
+ new RefcountedResource<SpiRecord>(
+ new SpiRecord(resourceId, direction, localAddress, remoteAddress, spi),
+ binder));
} catch (ServiceSpecificException e) {
// TODO: Add appropriate checks when other ServiceSpecificException types are supported
return new IpSecSpiResponse(
@@ -718,26 +876,17 @@
/* This method should only be called from Binder threads. Do not call this from
* within the system server as it will crash the system on failure.
*/
- private synchronized <T extends ManagedResource> void releaseManagedResource(
- ManagedResourceArray<T> resArray, int resourceId, String typeName)
+ private void releaseResource(RefcountedResourceArray resArray, int resourceId)
throws RemoteException {
- // We want to non-destructively get so that we can check credentials before removing
- // this from the records.
- T record = resArray.getAndCheckOwner(resourceId);
- if (record == null) {
- throw new IllegalArgumentException(
- typeName + " " + resourceId + " is not available to be deleted");
- }
-
- record.release();
- resArray.remove(resourceId);
+ resArray.getRefcountedResourceOrThrow(resourceId).userRelease();
}
/** Release a previously allocated SPI that has been registered with the system server */
@Override
- public void releaseSecurityParameterIndex(int resourceId) throws RemoteException {
- releaseManagedResource(mSpiRecords, resourceId, "SecurityParameterIndex");
+ public synchronized void releaseSecurityParameterIndex(int resourceId) throws RemoteException {
+ UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+ releaseResource(userRecord.mSpiRecords, resourceId);
}
/**
@@ -790,10 +939,11 @@
}
checkNotNull(binder, "Null Binder passed to openUdpEncapsulationSocket");
+ UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
int resourceId = mNextResourceId.getAndIncrement();
FileDescriptor sockFd = null;
try {
- if (!mUserQuotaTracker.getUserRecord(Binder.getCallingUid()).socket.isAvailable()) {
+ if (!userRecord.mSocketQuotaTracker.isAvailable()) {
return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
}
@@ -812,8 +962,10 @@
OsConstants.UDP_ENCAP,
OsConstants.UDP_ENCAP_ESPINUDP);
- mUdpSocketRecords.put(
- resourceId, new UdpSocketRecord(resourceId, binder, sockFd, port));
+ userRecord.mEncapSocketRecords.put(
+ resourceId,
+ new RefcountedResource<EncapSocketRecord>(
+ new EncapSocketRecord(resourceId, sockFd, port), binder));
return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port, sockFd);
} catch (IOException | ErrnoException e) {
IoUtils.closeQuietly(sockFd);
@@ -825,9 +977,9 @@
/** close a socket that has been been allocated by and registered with the system server */
@Override
- public void closeUdpEncapsulationSocket(int resourceId) throws RemoteException {
-
- releaseManagedResource(mUdpSocketRecords, resourceId, "UdpEncapsulationSocket");
+ public synchronized void closeUdpEncapsulationSocket(int resourceId) throws RemoteException {
+ UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+ releaseResource(userRecord.mEncapSocketRecords, resourceId);
}
/**
@@ -835,6 +987,8 @@
* IllegalArgumentException if they are not.
*/
private void checkIpSecConfig(IpSecConfig config) {
+ UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+
if (config.getLocalAddress() == null) {
throw new IllegalArgumentException("Invalid null Local InetAddress");
}
@@ -863,12 +1017,9 @@
break;
case IpSecTransform.ENCAP_ESPINUDP:
case IpSecTransform.ENCAP_ESPINUDP_NON_IKE:
- if (mUdpSocketRecords.getAndCheckOwner(
- config.getEncapSocketResourceId()) == null) {
- throw new IllegalStateException(
- "No Encapsulation socket for Resource Id: "
- + config.getEncapSocketResourceId());
- }
+ // Retrieve encap socket record; will throw IllegalArgumentException if not found
+ userRecord.mEncapSocketRecords.getResourceOrThrow(
+ config.getEncapSocketResourceId());
int port = config.getEncapRemotePort();
if (port <= 0 || port > 0xFFFF) {
@@ -892,9 +1043,8 @@
+ " exclusive with other Authentication or Encryption algorithms");
}
- if (mSpiRecords.getAndCheckOwner(config.getSpiResourceId(direction)) == null) {
- throw new IllegalStateException("No SPI for specified Resource Id");
- }
+ // Retrieve SPI record; will throw IllegalArgumentException if not found
+ userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId(direction));
}
}
@@ -911,16 +1061,27 @@
checkIpSecConfig(c);
checkNotNull(binder, "Null Binder passed to createTransportModeTransform");
int resourceId = mNextResourceId.getAndIncrement();
- if (!mUserQuotaTracker.getUserRecord(Binder.getCallingUid()).transform.isAvailable()) {
+
+ UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+
+ // Avoid resizing by creating a dependency array of min-size 3 (1 UDP encap + 2 SPIs)
+ List<RefcountedResource> dependencies = new ArrayList<>(3);
+
+ if (!userRecord.mTransformQuotaTracker.isAvailable()) {
return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
}
SpiRecord[] spis = new SpiRecord[DIRECTIONS.length];
int encapType, encapLocalPort = 0, encapRemotePort = 0;
- UdpSocketRecord socketRecord = null;
+ EncapSocketRecord socketRecord = null;
encapType = c.getEncapType();
if (encapType != IpSecTransform.ENCAP_NONE) {
- socketRecord = mUdpSocketRecords.getAndCheckOwner(c.getEncapSocketResourceId());
+ RefcountedResource<EncapSocketRecord> refcountedSocketRecord =
+ userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(
+ c.getEncapSocketResourceId());
+ dependencies.add(refcountedSocketRecord);
+
+ socketRecord = refcountedSocketRecord.getResource();
encapLocalPort = socketRecord.getPort();
encapRemotePort = c.getEncapRemotePort();
}
@@ -930,7 +1091,12 @@
IpSecAlgorithm crypt = c.getEncryption(direction);
IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(direction);
- spis[direction] = mSpiRecords.getAndCheckOwner(c.getSpiResourceId(direction));
+ RefcountedResource<SpiRecord> refcountedSpiRecord =
+ userRecord.mSpiRecords.getRefcountedResourceOrThrow(
+ c.getSpiResourceId(direction));
+ dependencies.add(refcountedSpiRecord);
+
+ spis[direction] = refcountedSpiRecord.getResource();
int spi = spis[direction].getSpi();
try {
mSrvConfig
@@ -961,8 +1127,12 @@
}
}
// Both SAs were created successfully, time to construct a record and lock it away
- mTransformRecords.put(
- resourceId, new TransformRecord(resourceId, binder, c, spis, socketRecord));
+ userRecord.mTransformRecords.put(
+ resourceId,
+ new RefcountedResource<TransformRecord>(
+ new TransformRecord(resourceId, c, spis, socketRecord),
+ binder,
+ dependencies.toArray(new RefcountedResource[dependencies.size()])));
return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId);
}
@@ -973,8 +1143,9 @@
* other reasons.
*/
@Override
- public void deleteTransportModeTransform(int resourceId) throws RemoteException {
- releaseManagedResource(mTransformRecords, resourceId, "IpSecTransform");
+ public synchronized void deleteTransportModeTransform(int resourceId) throws RemoteException {
+ UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+ releaseResource(userRecord.mTransformRecords, resourceId);
}
/**
@@ -984,14 +1155,10 @@
@Override
public synchronized void applyTransportModeTransform(
ParcelFileDescriptor socket, int resourceId) throws RemoteException {
- // Synchronize liberally here because we are using ManagedResources in this block
- TransformRecord info;
- // FIXME: this code should be factored out into a security check + getter
- info = mTransformRecords.getAndCheckOwner(resourceId);
+ UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
- if (info == null) {
- throw new IllegalArgumentException("Transform " + resourceId + " is not active");
- }
+ // Get transform record; if no transform is found, will throw IllegalArgumentException
+ TransformRecord info = userRecord.mTransformRecords.getResourceOrThrow(resourceId);
// TODO: make this a function.
if (info.pid != getCallingPid() || info.uid != getCallingUid()) {
@@ -1023,7 +1190,7 @@
* used: reserved for future improved input validation.
*/
@Override
- public void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId)
+ public synchronized void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId)
throws RemoteException {
try {
mSrvConfig
@@ -1042,13 +1209,7 @@
pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead"));
pw.println();
- pw.println("mUserQuotaTracker:");
- pw.println(mUserQuotaTracker);
- pw.println("mTransformRecords:");
- pw.println(mTransformRecords);
- pw.println("mUdpSocketRecords:");
- pw.println(mUdpSocketRecords);
- pw.println("mSpiRecords:");
- pw.println(mSpiRecords);
+ pw.println("mUserResourceTracker:");
+ pw.println(mUserResourceTracker);
}
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index bdfccd6e..0a86281 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.util.ArrayMap;
import android.util.ArraySet;
+
import com.android.internal.content.PackageMonitor;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
@@ -147,7 +148,7 @@
private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
private static final int FOREGROUND_IMPORTANCE_CUTOFF
- = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+ = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
// default background throttling interval if not overriden in settings
private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
@@ -239,7 +240,7 @@
// current active user on the device - other users are denied location data
private int mCurrentUserId = UserHandle.USER_SYSTEM;
- private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
+ private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
@@ -253,7 +254,7 @@
public LocationManagerService(Context context) {
super();
mContext = context;
- mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
+ mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
// Let the package manager query which are the default location
// providers as they get certain permissions granted by default.
@@ -370,18 +371,18 @@
}
}, UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(
- Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
- true,
- new ContentObserver(mLocationHandler) {
- @Override
- public void onChange(boolean selfChange) {
- synchronized (mLock) {
- updateBackgroundThrottlingWhitelistLocked();
- updateProvidersLocked();
+ Settings.Global.getUriFor(
+ Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
+ true,
+ new ContentObserver(mLocationHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ synchronized (mLock) {
+ updateBackgroundThrottlingWhitelistLocked();
+ updateProvidersLocked();
+ }
}
- }
- }, UserHandle.USER_ALL);
+ }, UserHandle.USER_ALL);
mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
// listen for user change
@@ -402,7 +403,7 @@
updateUserProfiles(mCurrentUserId);
} else if (Intent.ACTION_SHUTDOWN.equals(action)) {
// shutdown only if UserId indicates whole system, not just one user
- if(D) Log.d(TAG, "Shutdown received with UserId: " + getSendingUserId());
+ if (D) Log.d(TAG, "Shutdown received with UserId: " + getSendingUserId());
if (getSendingUserId() == UserHandle.USER_ALL) {
shutdownComponents();
}
@@ -416,13 +417,15 @@
HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
synchronized (mLock) {
for (Entry<String, ArrayList<UpdateRecord>> entry
- : mRecordsByProvider.entrySet()) {
+ : mRecordsByProvider.entrySet()) {
String provider = entry.getKey();
for (UpdateRecord record : entry.getValue()) {
if (record.mReceiver.mIdentity.mUid == uid
- && record.mIsForegroundUid != foreground) {
- if (D) Log.d(TAG, "request from uid " + uid + " is now "
- + (foreground ? "foreground" : "background)"));
+ && record.mIsForegroundUid != foreground) {
+ if (D) {
+ Log.d(TAG, "request from uid " + uid + " is now "
+ + (foreground ? "foreground" : "background)"));
+ }
record.mIsForegroundUid = foreground;
if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
@@ -436,10 +439,12 @@
}
for (Entry<IGnssMeasurementsListener, Identity> entry
- : mGnssMeasurementsListeners.entrySet()) {
+ : mGnssMeasurementsListeners.entrySet()) {
if (entry.getValue().mUid == uid) {
- if (D) Log.d(TAG, "gnss measurements listener from uid " + uid
- + " is now " + (foreground ? "foreground" : "background)"));
+ if (D) {
+ Log.d(TAG, "gnss measurements listener from uid " + uid
+ + " is now " + (foreground ? "foreground" : "background)"));
+ }
if (foreground || isThrottlingExemptLocked(entry.getValue())) {
mGnssMeasurementsProvider.addListener(entry.getKey());
} else {
@@ -449,11 +454,13 @@
}
for (Entry<IGnssNavigationMessageListener, Identity> entry
- : mGnssNavigationMessageListeners.entrySet()) {
+ : mGnssNavigationMessageListeners.entrySet()) {
if (entry.getValue().mUid == uid) {
- if (D) Log.d(TAG, "gnss navigation message listener from uid "
- + uid + " is now "
- + (foreground ? "foreground" : "background)"));
+ if (D) {
+ Log.d(TAG, "gnss navigation message listener from uid "
+ + uid + " is now "
+ + (foreground ? "foreground" : "background)"));
+ }
if (foreground || isThrottlingExemptLocked(entry.getValue())) {
mGnssNavigationMessageProvider.addListener(entry.getKey());
} else {
@@ -477,7 +484,7 @@
* support for components that do not wish to handle such event.
*/
private void shutdownComponents() {
- if(D) Log.d(TAG, "Shutting down components...");
+ if (D) Log.d(TAG, "Shutting down components...");
LocationProviderInterface gpsProvider = mProvidersByName.get(LocationManager.GPS_PROVIDER);
if (gpsProvider != null && gpsProvider.isEnabled()) {
@@ -563,8 +570,10 @@
// as a proxy for coreApp="true"
if (pm.checkSignatures(systemPackageName, packageName)
!= PackageManager.SIGNATURE_MATCH) {
- if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
- + packageName);
+ if (D) {
+ Log.d(TAG, "Fallback candidate not signed the same as system: "
+ + packageName);
+ }
continue;
}
@@ -622,8 +631,10 @@
ArrayList<String> providerPackageNames = new ArrayList<>();
String[] pkgs = resources.getStringArray(
com.android.internal.R.array.config_locationProviderPackageNames);
- if (D) Log.d(TAG, "certificates for location providers pulled from: " +
- Arrays.toString(pkgs));
+ if (D) {
+ Log.d(TAG, "certificates for location providers pulled from: " +
+ Arrays.toString(pkgs));
+ }
if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
ensureFallbackFusedProviderPresentLocked(providerPackageNames);
@@ -642,7 +653,7 @@
mProxyProviders.add(networkProvider);
addProviderLocked(networkProvider);
} else {
- Slog.w(TAG, "no network location provider found");
+ Slog.w(TAG, "no network location provider found");
}
// bind to fused provider
@@ -671,7 +682,7 @@
com.android.internal.R.array.config_locationProviderPackageNames,
mLocationHandler);
if (mGeocodeProvider == null) {
- Slog.e(TAG, "no geocoder provider found");
+ Slog.e(TAG, "no geocoder provider found");
}
// bind to fused hardware provider if supported
@@ -697,14 +708,14 @@
// bind to geofence provider
GeofenceProxy provider = GeofenceProxy.createAndBind(
- mContext,com.android.internal.R.bool.config_enableGeofenceOverlay,
+ mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
com.android.internal.R.string.config_geofenceProviderPackageName,
com.android.internal.R.array.config_locationProviderPackageNames,
mLocationHandler,
mGpsGeofenceProxy,
flpHardwareProvider != null ? flpHardwareProvider.getGeofenceHardware() : null);
if (provider == null) {
- Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
+ Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
}
// bind to hardware activity recognition
@@ -751,6 +762,7 @@
/**
* Called when the device's active user changes.
+ *
* @param userId the new active user's UserId
*/
private void switchUser(int userId) {
@@ -797,7 +809,7 @@
final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
final Object mKey;
- final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<>();
+ final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
// True if app ops has started monitoring this receiver for locations.
boolean mOpMonitoring;
@@ -914,9 +926,9 @@
/**
* Update AppOps monitoring for a single location request and op type.
*
- * @param allowMonitoring True if monitoring is allowed for this request/op.
+ * @param allowMonitoring True if monitoring is allowed for this request/op.
* @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
- * @param op AppOps code for the op to update.
+ * @param op AppOps code for the op to update.
* @return True if monitoring is on for this request/op after updating.
*/
private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
@@ -1004,7 +1016,8 @@
}
} else {
Intent locationChanged = new Intent();
- locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
+ locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
+ new Location(location));
try {
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
@@ -1286,7 +1299,7 @@
}
if (mGnssBatchingProvider != null) {
- mGnssBatchingProvider.flush();
+ mGnssBatchingProvider.flush();
}
}
@@ -1301,7 +1314,7 @@
if (mGnssBatchingProvider != null) {
mGnssBatchingInProgress = false;
return mGnssBatchingProvider.stop();
- } else {
+ } else {
return false;
}
}
@@ -1363,7 +1376,7 @@
* processes belonging to background users.
*
* @param provider the name of the location provider
- * @param uid the requestor's UID
+ * @param uid the requestor's UID
*/
private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
@@ -1467,7 +1480,7 @@
* location provider.
*
* @param allowedResolutionLevel resolution level allowed to caller
- * @param providerName the name of the location provider
+ * @param providerName the name of the location provider
*/
private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
String providerName) {
@@ -1718,7 +1731,9 @@
resolver,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
+ // initialize the low power mode to true and set to false if any of the records requires
+ providerRequest.lowPowerMode = true;
if (records != null) {
for (UpdateRecord record : records) {
if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
@@ -1742,6 +1757,9 @@
record.mRequest = locationRequest;
providerRequest.locationRequests.add(locationRequest);
+ if (!locationRequest.isLowPowerMode()) {
+ providerRequest.lowPowerMode = false;
+ }
if (interval < providerRequest.interval) {
providerRequest.reportLocation = true;
providerRequest.interval = interval;
@@ -1794,23 +1812,23 @@
public String[] getBackgroundThrottlingWhitelist() {
synchronized (mLock) {
return mBackgroundThrottlePackageWhitelist.toArray(
- new String[mBackgroundThrottlePackageWhitelist.size()]);
+ new String[mBackgroundThrottlePackageWhitelist.size()]);
}
}
private void updateBackgroundThrottlingWhitelistLocked() {
String setting = Settings.Global.getString(
- mContext.getContentResolver(),
- Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
+ mContext.getContentResolver(),
+ Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
if (setting == null) {
setting = "";
}
mBackgroundThrottlePackageWhitelist.clear();
mBackgroundThrottlePackageWhitelist.addAll(
- SystemConfig.getInstance().getAllowUnthrottledLocation());
+ SystemConfig.getInstance().getAllowUnthrottledLocation());
mBackgroundThrottlePackageWhitelist.addAll(
- Arrays.asList(setting.split(",")));
+ Arrays.asList(setting.split(",")));
}
private boolean isThrottlingExemptLocked(Identity identity) {
@@ -1894,7 +1912,8 @@
@Override
public String toString() {
return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
- + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground" : " background")
+ + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
+ : " background")
+ ")" + " " + mRealRequest + "]";
}
}
@@ -1936,8 +1955,13 @@
* @return a version of request that meets the given resolution and consistency requirements
* @hide
*/
- private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
+ private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
+ boolean callerHasLocationHardwarePermission) {
LocationRequest sanitizedRequest = new LocationRequest(request);
+ if (!callerHasLocationHardwarePermission) {
+ // allow setting low power mode only for callers with location hardware permission
+ sanitizedRequest.setLowPowerMode(false);
+ }
if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
switch (sanitizedRequest.getQuality()) {
case LocationRequest.ACCURACY_FINE:
@@ -2013,7 +2037,11 @@
if (hideFromAppOps) {
checkUpdateAppOpsAllowed();
}
- LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
+ boolean callerHasLocationHardwarePermission =
+ mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ == PackageManager.PERMISSION_GRANTED;
+ LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
+ callerHasLocationHardwarePermission);
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
@@ -2050,11 +2078,13 @@
}
UpdateRecord record = new UpdateRecord(name, request, receiver);
- if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
- + " " + name + " " + request + " from " + packageName + "(" + uid + " "
- + (record.mIsForegroundUid ? "foreground" : "background")
- + (isThrottlingExemptLocked(receiver.mIdentity)
+ if (D) {
+ Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
+ + " " + name + " " + request + " from " + packageName + "(" + uid + " "
+ + (record.mIsForegroundUid ? "foreground" : "background")
+ + (isThrottlingExemptLocked(receiver.mIdentity)
? " [whitelisted]" : "") + ")");
+ }
UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
if (oldRecord != null) {
@@ -2159,14 +2189,18 @@
final long identity = Binder.clearCallingIdentity();
try {
if (mBlacklist.isBlacklisted(packageName)) {
- if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
- packageName);
+ if (D) {
+ Log.d(TAG, "not returning last loc for blacklisted app: " +
+ packageName);
+ }
return null;
}
if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
- if (D) Log.d(TAG, "not returning last loc for no op app: " +
- packageName);
+ if (D) {
+ Log.d(TAG, "not returning last loc for no op app: " +
+ packageName);
+ }
return null;
}
@@ -2192,7 +2226,8 @@
return null;
}
if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
- Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
+ Location noGPSLocation = location.getExtraLocation(
+ Location.EXTRA_NO_GPS_LOCATION);
if (noGPSLocation != null) {
return new Location(mLocationFudger.getOrCreate(noGPSLocation));
}
@@ -2216,7 +2251,12 @@
checkPackageName(packageName);
checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
request.getProvider());
- LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
+ // Require that caller can manage given document
+ boolean callerHasLocationHardwarePermission =
+ mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ == PackageManager.PERMISSION_GRANTED;
+ LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
+ callerHasLocationHardwarePermission);
if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
@@ -2282,8 +2322,7 @@
@Override
public boolean addGnssMeasurementsListener(
- IGnssMeasurementsListener listener,
- String packageName) {
+ IGnssMeasurementsListener listener, String packageName) {
if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
return false;
}
@@ -2296,7 +2335,7 @@
try {
if (isThrottlingExemptLocked(callerIdentity)
|| isImportanceForeground(
- mActivityManager.getPackageImportance(packageName))) {
+ mActivityManager.getPackageImportance(packageName))) {
return mGnssMeasurementsProvider.addListener(listener);
}
} finally {
@@ -2327,13 +2366,13 @@
synchronized (mLock) {
Identity callerIdentity
- = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+ = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
mGnssNavigationMessageListeners.put(listener, callerIdentity);
long identity = Binder.clearCallingIdentity();
try {
if (isThrottlingExemptLocked(callerIdentity)
|| isImportanceForeground(
- mActivityManager.getPackageImportance(packageName))) {
+ mActivityManager.getPackageImportance(packageName))) {
return mGnssNavigationMessageProvider.addListener(listener);
}
} finally {
@@ -2394,7 +2433,7 @@
/**
* @return null if the provider does not exist
* @throws SecurityException if the provider is not allowed to be
- * accessed by the caller
+ * accessed by the caller
*/
@Override
public ProviderProperties getProviderProperties(String provider) {
@@ -2417,7 +2456,7 @@
/**
* @return null if the provider does not exist
* @throws SecurityException if the provider is not allowed to be
- * accessed by the caller
+ * accessed by the caller
*/
@Override
public String getNetworkProviderPackage() {
@@ -2641,8 +2680,10 @@
}
if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
- if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
- receiver.mIdentity.mPackageName);
+ if (D) {
+ Log.d(TAG, "skipping loc update for blacklisted app: " +
+ receiver.mIdentity.mPackageName);
+ }
continue;
}
@@ -2651,8 +2692,10 @@
receiver.mIdentity.mUid,
receiver.mIdentity.mPackageName,
receiver.mAllowedResolutionLevel)) {
- if (D) Log.d(TAG, "skipping loc update for no op app: " +
- receiver.mIdentity.mPackageName);
+ if (D) {
+ Log.d(TAG, "skipping loc update for no op app: " +
+ receiver.mIdentity.mPackageName);
+ }
continue;
}
@@ -3114,12 +3157,12 @@
}
pw.append(" fudger: ");
- mLocationFudger.dump(fd, pw, args);
+ mLocationFudger.dump(fd, pw, args);
if (args.length > 0 && "short".equals(args[0])) {
return;
}
- for (LocationProviderInterface provider: mProviders) {
+ for (LocationProviderInterface provider : mProviders) {
pw.print(provider.getName() + " Internal State");
if (provider instanceof LocationProviderProxy) {
LocationProviderProxy proxy = (LocationProviderProxy) provider;
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 296fb32..a2c0506 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -1,13 +1,19 @@
# Connectivity / Networking
per-file ConnectivityService.java=ek@google.com
per-file ConnectivityService.java=hugobenichi@google.com
+per-file ConnectivityService.java=jchalard@google.com
per-file ConnectivityService.java=lorenzo@google.com
+per-file ConnectivityService.java=satk@google.com
per-file NetworkManagementService.java=ek@google.com
per-file NetworkManagementService.java=hugobenichi@google.com
+per-file NetworkManagementService.java=jchalard@google.com
per-file NetworkManagementService.java=lorenzo@google.com
+per-file NetworkManagementService.java=satk@google.com
per-file NsdService.java=ek@google.com
per-file NsdService.java=hugobenichi@google.com
+per-file NsdService.java=jchalard@google.com
per-file NsdService.java=lorenzo@google.com
+per-file NsdService.java=satk@google.com
# Vibrator
per-file VibratorService.java=michaelwr@google.com
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 66b3adb..7f0b508 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2611,6 +2611,7 @@
try {
mVold.mkdirs(appPath);
+ return;
} catch (Exception 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/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 0d4f5cb..0ffc779 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2118,13 +2118,14 @@
userId));
}
/*
- * Only the system or authenticator should be allowed to remove accounts for that
- * authenticator. This will let users remove accounts (via Settings in the system) but not
- * arbitrary applications (like competing authenticators).
+ * Only the system, authenticator or profile owner should be allowed to remove accounts for
+ * that authenticator. This will let users remove accounts (via Settings in the system) but
+ * not arbitrary applications (like competing authenticators).
*/
UserHandle user = UserHandle.of(userId);
if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
- && !isSystemUid(callingUid)) {
+ && !isSystemUid(callingUid)
+ && !isProfileOwner(callingUid)) {
String msg = String.format(
"uid %s cannot remove accounts of type: %s",
callingUid,
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index b11b16e1..5f2f3af 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,15 +409,16 @@
otherStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
}
} finally {
- if (mHomeStack != null && !isTopStack(mHomeStack)) {
+ final ActivityStack topFullscreenStack =
+ getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ if (topFullscreenStack != null && 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();
+ // current top fullscreen stack so it shows up when the top stack is finished.
// 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");
+ topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
}
mSupervisor.mWindowManager.continueSurfaceLayout();
}
@@ -423,7 +434,9 @@
|| !otherStack.affectedBySplitScreenResize()) {
continue;
}
- otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
+ false /* animate */, false /* showRecents */,
+ true /* enteringSplitScreenMode */);
}
} 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 fe992da..9366f6e 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;
@@ -398,6 +400,7 @@
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.MemInfoReader;
import com.android.internal.util.Preconditions;
+import com.android.server.AlarmManagerInternal;
import com.android.server.AppOpsService;
import com.android.server.AttributeCache;
import com.android.server.DeviceIdleController;
@@ -414,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;
@@ -466,6 +471,7 @@
import java.util.concurrent.atomic.AtomicLong;
import dalvik.system.VMRuntime;
+
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
@@ -623,7 +629,13 @@
/** All system services */
SystemServiceManager mSystemServiceManager;
- AssistUtils mAssistUtils;
+
+ // Wrapper around VoiceInteractionServiceManager
+ private AssistUtils mAssistUtils;
+
+ // Keeps track of the active voice interaction service component, notified from
+ // VoiceInteractionManagerService
+ ComponentName mActiveVoiceInteractionServiceComponent;
private Installer mInstaller;
@@ -631,7 +643,7 @@
final ActivityStackSupervisor mStackSupervisor;
private final KeyguardController mKeyguardController;
- final ActivityStarter mActivityStarter;
+ private final ActivityStartController mActivityStartController;
final ClientLifecycleManager mLifecycleManager;
@@ -1360,7 +1372,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;
@@ -1706,7 +1718,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;
@@ -2076,11 +2087,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;
@@ -2569,14 +2575,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);
}
};
@@ -2677,7 +2682,7 @@
mContext = mInjector.getContext();
mUiContext = null;
GL_ES_VERSION = 0;
- mActivityStarter = null;
+ mActivityStartController = null;
mAppErrors = null;
mAppWarnings = null;
mAppOpsService = mInjector.getAppOpsService(null, null);
@@ -2801,7 +2806,7 @@
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);
@@ -4121,7 +4126,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());
@@ -4154,49 +4159,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) {
@@ -4562,9 +4530,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
@@ -4625,11 +4602,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
@@ -4655,9 +4638,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;
}
@@ -4669,10 +4661,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
@@ -4718,9 +4717,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
@@ -4729,9 +4735,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
@@ -4771,9 +4781,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);
@@ -4946,11 +4959,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;
@@ -4976,20 +5000,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,
@@ -4999,21 +5009,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;
}
@@ -5958,7 +5955,7 @@
}
@Override
- public boolean clearApplicationUserData(final String packageName,
+ public boolean clearApplicationUserData(final String packageName, boolean keepState,
final IPackageDataObserver observer, int userId) {
enforceNotIsolatedCaller("clearApplicationUserData");
int uid = Binder.getCallingUid();
@@ -6062,14 +6059,27 @@
pm.clearApplicationUserData(packageName, localObserver, resolvedUserId);
if (appInfo != null) {
- synchronized (this) {
- // Remove all permissions granted from/to this package
- removeUriPermissionsForPackageLocked(packageName, resolvedUserId, true);
+ // Restore already established notification state and permission grants,
+ // so it told us to keep those intact -- it's about to emplace app data
+ // that is appropriate for those bits of system state.
+ if (!keepState) {
+ synchronized (this) {
+ // Remove all permissions granted from/to this package
+ removeUriPermissionsForPackageLocked(packageName, resolvedUserId, true);
+ }
+
+ // Reset notification state
+ INotificationManager inm = NotificationManager.getService();
+ inm.clearData(packageName, appInfo.uid, uid == appInfo.uid);
}
- // Reset notification settings.
- INotificationManager inm = NotificationManager.getService();
- inm.clearData(packageName, appInfo.uid, uid == appInfo.uid);
+ // Clear its scheduled jobs
+ JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
+ js.cancelJobsForUid(appInfo.uid, "clear data");
+
+ // Clear its pending alarms
+ AlarmManagerInternal ami = LocalServices.getService(AlarmManagerInternal.class);
+ ami.removeAlarmsForUid(uid);
}
} catch (RemoteException e) {
}
@@ -6667,7 +6677,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)) {
@@ -8887,7 +8897,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");
@@ -10031,7 +10044,7 @@
}
}
- TaskRecord task = new TaskRecord(this,
+ TaskRecord task = TaskRecord.create(this,
mStackSupervisor.getNextTaskIdForUserLocked(r.userId),
ainfo, intent, description);
if (!mRecentTasks.addToBottom(task)) {
@@ -10501,7 +10514,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()");
@@ -10547,10 +10560,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) {
@@ -10575,7 +10590,8 @@
if (toTop) {
stack.moveToFront("setTaskWindowingModeSplitScreenPrimary", task);
}
- stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, animate);
+ stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, animate, showRecents,
+ false /* enteringSplitScreenMode */);
return windowingMode != task.getWindowingMode();
} finally {
Binder.restoreCallingIdentity(ident);
@@ -11755,6 +11771,10 @@
return AppGlobals.getPackageManager();
}
+ ActivityStartController getActivityStartController() {
+ return mActivityStartController;
+ }
+
PackageManagerInternal getPackageManagerInternalLocked() {
if (mPackageManagerInt == null) {
mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
@@ -12604,7 +12624,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);
}
@@ -12623,9 +12652,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);
}
}
@@ -13696,7 +13723,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);
}
}
}
@@ -14595,7 +14623,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(")");
}
@@ -15490,7 +15518,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,
@@ -17207,8 +17235,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;
@@ -17221,7 +17249,7 @@
opts.packages = false;
opts.isCheckinRequest = false;
opts.dumpSwapPss = false;
- opts.dumpProto = false;
+ opts.dumpProto = asProto;
int opti = 0;
while (opti < args.length) {
@@ -17289,7 +17317,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();
@@ -17298,54 +17326,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;
}
@@ -17768,15 +17801,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,
@@ -20154,6 +20249,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;
@@ -20600,7 +20700,7 @@
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
+ app.processName + " new config " + configCopy);
mLifecycleManager.scheduleTransaction(app.thread,
- new ConfigurationChangeItem(configCopy));
+ ConfigurationChangeItem.obtain(configCopy));
}
} catch (Exception e) {
Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change", e);
@@ -23810,7 +23910,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
@@ -24180,8 +24286,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);
}
}
@@ -24306,6 +24412,13 @@
}
}
+ @Override
+ public void notifyActiveVoiceInteractionServiceChanged(ComponentName component) {
+ synchronized (ActivityManagerService.this) {
+ mActiveVoiceInteractionServiceComponent = component;
+ }
+ }
+
/**
* Called after virtual display Id is updated by
* {@link com.android.server.vr.Vr2dDisplay} with a specific
@@ -24332,7 +24445,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 */,
@@ -24392,6 +24505,26 @@
public boolean isRuntimeRestarted() {
return mSystemServiceManager.isRuntimeRestarted();
}
+
+ @Override
+ public boolean hasRunningActivity(int uid, @Nullable String packageName) {
+ if (packageName == null) return false;
+
+ synchronized (ActivityManagerService.this) {
+ for (int i = 0; i < mLruProcesses.size(); i++) {
+ final ProcessRecord processRecord = mLruProcesses.get(i);
+ if (processRecord.uid == uid) {
+ for (int j = 0; j < processRecord.activities.size(); j++) {
+ final ActivityRecord activityRecord = processRecord.activities.get(j);
+ if (packageName.equals(activityRecord.packageName)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 7eb922c..54938eb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -69,7 +69,9 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
import static android.app.ActivityManager.RESIZE_MODE_USER;
@@ -224,6 +226,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 +1830,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 +1867,56 @@
}
String packageName = getNextArgRequired();
String value = getNextArgRequired();
+ int bucket = bucketNameToBucketValue(value);
+ if (bucket < 0) return -1;
+ boolean multiple = peekNextArg() != null;
+
IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(
Context.USAGE_STATS_SERVICE));
- usm.setAppStandbyBucket(packageName, Integer.parseInt(value), userId);
+ if (!multiple) {
+ usm.setAppStandbyBucket(packageName, bucketNameToBucketValue(value), userId);
+ } else {
+ HashMap<String, Integer> buckets = new HashMap<>();
+ buckets.put(packageName, bucket);
+ while ((packageName = getNextArg()) != null) {
+ value = getNextArgRequired();
+ bucket = bucketNameToBucketValue(value);
+ if (bucket < 0) continue;
+ buckets.put(packageName, bucket);
+ }
+ usm.setAppStandbyBuckets(buckets, 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 = getNextArg();
+
+ IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(
+ Context.USAGE_STATS_SERVICE));
+ if (packageName != null) {
+ int bucket = usm.getAppStandbyBucket(packageName, null, userId);
+ pw.println(bucket);
+ } else {
+ Map<String, Integer> buckets = (Map<String, Integer>) usm.getAppStandbyBuckets(
+ SHELL_PACKAGE_NAME, userId);
+ for (Map.Entry<String, Integer> entry: buckets.entrySet()) {
+ pw.print(entry.getKey()); pw.print(": ");
+ pw.println(entry.getValue());
+ }
+ }
return 0;
}
@@ -2597,8 +2670,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 a089e6c..d42c5de 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -618,7 +618,7 @@
+ ", displayId=" + displayId + ", config=" + config);
service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
- new MoveToDisplayItem(displayId, config));
+ MoveToDisplayItem.obtain(displayId, config));
} catch (RemoteException e) {
// If process died, whatever.
}
@@ -636,7 +636,7 @@
+ config);
service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
- new ActivityConfigurationChangeItem(config));
+ ActivityConfigurationChangeItem.obtain(config));
} catch (RemoteException e) {
// If process died, whatever.
}
@@ -663,7 +663,7 @@
private void scheduleMultiWindowModeChanged(Configuration overrideConfig) {
try {
service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
- new MultiWindowModeChangeItem(mLastReportedMultiWindowMode,
+ MultiWindowModeChangeItem.obtain(mLastReportedMultiWindowMode,
overrideConfig));
} catch (Exception e) {
// If process died, I don't care.
@@ -691,7 +691,7 @@
private void schedulePictureInPictureModeChanged(Configuration overrideConfig) {
try {
service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
- new PipModeChangeItem(mLastReportedPictureInPictureMode,
+ PipModeChangeItem.obtain(mLastReportedPictureInPictureMode,
overrideConfig));
} catch (Exception e) {
// If process died, no one cares.
@@ -1050,11 +1050,7 @@
* @return whether the given package name can launch an assist activity.
*/
private boolean canLaunchAssistActivity(String packageName) {
- if (service.mAssistUtils == null) {
- return false;
- }
-
- final ComponentName assistComponent = service.mAssistUtils.getActiveServiceComponentName();
+ final ComponentName assistComponent = service.mActiveVoiceInteractionServiceComponent;
if (assistComponent != null) {
return assistComponent.getPackageName().equals(packageName);
}
@@ -1380,7 +1376,7 @@
ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
ar.add(rintent);
service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
- new NewIntentItem(ar, state == PAUSED));
+ NewIntentItem.obtain(ar, state == PAUSED));
unsent = false;
} catch (RemoteException e) {
Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
@@ -1603,7 +1599,7 @@
sleeping = false;
app.pendingUiClean = true;
service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
- new WindowVisibilityItem(true /* showWindow */));
+ 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 ced8621..27bd9b7 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -144,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;
@@ -482,32 +483,46 @@
@Override
public void setWindowingMode(int windowingMode) {
- setWindowingMode(windowingMode, false /* animate */);
+ setWindowingMode(windowingMode, false /* animate */, true /* showRecents */,
+ false /* enteringSplitScreenMode */);
}
- void setWindowingMode(int preferredWindowingMode, boolean animate) {
+ void setWindowingMode(int preferredWindowingMode, boolean animate, boolean showRecents,
+ boolean enteringSplitScreenMode) {
+ final boolean creating = mWindowContainerController == null;
final int currentMode = getWindowingMode();
final ActivityDisplay display = getDisplay();
final TaskRecord topTask = topTask();
final ActivityStack splitScreenStack = display.getSplitScreenPrimaryStack();
mTmpOptions.setLaunchWindowingMode(preferredWindowingMode);
- // Need to make sure windowing mode is supported.
- int windowingMode = display.resolveWindowingMode(
- null /* ActivityRecord */, mTmpOptions, topTask, getActivityType());
+ // Need to make sure windowing mode is supported. If we in the process of creating the stack
+ // no need to resolve the windowing mode again as it is already resolved to the right mode.
+ int windowingMode = creating
+ ? preferredWindowingMode
+ : display.resolveWindowingMode(
+ 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();
+
+ // Don't send non-resizeable notifications if the windowing mode changed was a side effect
+ // of us entering split-screen mode.
+ final boolean sendNonResizeableNotification = !enteringSplitScreenMode;
// Take any required action due to us not supporting the preferred windowing mode.
- if (windowingMode != preferredWindowingMode && isActivityTypeStandardOrUndefined()) {
- if (display.hasSplitScreenPrimaryStack()
- && (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
- // and display a warning toast about it.
+ if (alreadyInSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
+ && sendNonResizeableNotification && isActivityTypeStandardOrUndefined()) {
+ final boolean preferredSplitScreen =
+ preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+ if (preferredSplitScreen || creating) {
+ // Looks like we can't launch in split screen mode or the stack we are launching
+ // doesn't support split-screen mode, go ahead an dismiss split-screen and display a
+ // warning toast about it.
mService.mTaskChangeNotificationController.notifyActivityDismissingDockedStack();
display.getSplitScreenPrimaryStack().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
}
@@ -521,8 +536,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;
@@ -537,7 +553,7 @@
}
super.setWindowingMode(windowingMode);
- if (mWindowContainerController == null) {
+ if (creating) {
// Nothing else to do if we don't have a window container yet. E.g. call from ctor.
return;
}
@@ -577,7 +593,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
@@ -587,16 +603,22 @@
// the one where the home stack is visible since recents isn't visible yet, but the
// divider will be off. I think we should just make the initial bounds that of home
// so that the divider matches and remove this logic.
- display.getOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
- ACTIVITY_TYPE_RECENTS, true /* onTop */);
+ final ActivityStack recentStack = display.getOrCreateStack(
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_RECENTS,
+ true /* onTop */);
+ recentStack.moveToFront("setWindowingMode");
// If task moved to docked stack - show recents if needed.
mService.mWindowManager.showRecentApps(false /* fromHome */);
}
wm.continueSurfaceLayout();
}
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
+ // Don't ensure visible activities if the windowing mode change was a side effect of us
+ // entering split-screen mode.
+ if (!enteringSplitScreenMode) {
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
+ }
}
@Override
@@ -1422,13 +1444,12 @@
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);
mService.mLifecycleManager.scheduleTransaction(prev.app.thread, prev.appToken,
- new PauseActivityItem(prev.finishing, userLeaving,
+ PauseActivityItem.obtain(prev.finishing, userLeaving,
prev.configChangeFlags, pauseImmediately));
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
@@ -1678,12 +1699,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);
}
@@ -2065,7 +2080,7 @@
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Scheduling invisibility: " + r);
mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken,
- new WindowVisibilityItem(false /* showWindow */));
+ WindowVisibilityItem.obtain(false /* showWindow */));
}
// Reset the flag indicating that an app can enter picture-in-picture once the
@@ -2264,7 +2279,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) {
@@ -2335,6 +2350,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 */);
}
@@ -2586,13 +2608,13 @@
if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
"Delivering results to " + next + ": " + a);
mService.mLifecycleManager.scheduleTransaction(next.app.thread,
- next.appToken, new ActivityResultItem(a));
+ next.appToken, ActivityResultItem.obtain(a));
}
}
if (next.newIntents != null) {
mService.mLifecycleManager.scheduleTransaction(next.app.thread,
- next.appToken, new NewIntentItem(next.newIntents,
+ next.appToken, NewIntentItem.obtain(next.newIntents,
false /* andPause */));
}
@@ -2611,7 +2633,7 @@
next.app.forceProcessStateUpTo(mService.mTopProcessState);
next.clearOptionsLocked();
mService.mLifecycleManager.scheduleTransaction(next.app.thread, next.appToken,
- new ResumeActivityItem(next.app.repProcState,
+ ResumeActivityItem.obtain(next.app.repProcState,
mService.isNextTransitionForward()));
if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
@@ -3263,7 +3285,7 @@
list.add(new ResultInfo(resultWho, requestCode,
resultCode, data));
mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken,
- new ActivityResultItem(list));
+ ActivityResultItem.obtain(list));
return;
} catch (Exception e) {
Slog.w(TAG, "Exception thrown sending result to " + r, e);
@@ -3392,7 +3414,7 @@
EventLogTags.writeAmStopActivity(
r.userId, System.identityHashCode(r), r.shortComponentName);
mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken,
- new StopActivityItem(r.visible, r.configChangeFlags));
+ StopActivityItem.obtain(r.visible, r.configChangeFlags));
if (shouldSleepOrShutDownActivities()) {
r.setSleeping(true);
}
@@ -3896,11 +3918,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;
@@ -4190,7 +4220,7 @@
try {
if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + r);
mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken,
- new DestroyActivityItem(r.finishing, r.configChangeFlags));
+ 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
@@ -5011,8 +5041,8 @@
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
boolean toTop, ActivityRecord activity, ActivityRecord source,
ActivityOptions options) {
- final TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
- voiceInteractor);
+ 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()
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 445bf67..edaa511 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -114,7 +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;
@@ -129,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;
@@ -298,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
@@ -364,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
@@ -978,7 +982,7 @@
}
}
// Send launch end powerhint when idle
- mService.mActivityStarter.sendPowerHintForLaunchEndIfNeeded();
+ sendPowerHintForLaunchEndIfNeeded();
return true;
}
@@ -1235,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);
+ }
}
}
@@ -1393,16 +1404,33 @@
r.setLastReportedConfiguration(mergedConfiguration);
logIfTransactionTooLarge(r.intent, r.icicle);
- mService.mLifecycleManager.scheduleTransaction(app.thread, r.appToken,
- new LaunchActivityItem(new Intent(r.intent),
+
+
+ // 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
@@ -1470,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
@@ -1531,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,
@@ -2481,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();
@@ -2875,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.
*
@@ -3335,7 +3379,7 @@
}
// Send launch end powerhint before going sleep
- mService.mActivityStarter.sendPowerHintForLaunchEndIfNeeded();
+ sendPowerHintForLaunchEndIfNeeded();
removeSleepTimeouts();
@@ -4473,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);
}
@@ -4532,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,
@@ -4550,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;
@@ -4559,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..aed49e0
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -0,0 +1,421 @@
+/*
+ * 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) {
+ return mFactory.obtain().setIntent(intent).setReason(reason);
+ }
+
+ void onExecutionComplete(ActivityStarter starter) {
+ if (mLastStarter == null) {
+ mLastStarter = mFactory.obtain();
+ }
+
+ mLastStarter.set(starter);
+ mFactory.recycle(starter);
+ }
+
+ /**
+ * 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) {
+ if (mLastStarter == null) {
+ return;
+ }
+
+ 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 27eb985..69cc3c7 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,25 +86,26 @@
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;
import android.text.TextUtils;
import android.util.EventLog;
+import android.util.Pools.SynchronizedPool;
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 +113,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.
@@ -136,8 +132,7 @@
private final ActivityManagerService mService;
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,323 @@
// 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();
+ /**
+ * 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 obtain();
- 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;
+ /**
+ * Recycles a starter for reuse.
+ */
+ void recycle(ActivityStarter starter);
}
- ActivityStarter(ActivityManagerService service) {
+ /**
+ * Default implementation of {@link StarterFactory}.
+ */
+ static class DefaultFactory implements Factory {
+ /**
+ * The maximum count of starters that should be active at one time:
+ * 1. last ran starter (for logging and post activity processing)
+ * 2. current running starter
+ * 3. starter from re-entry in (2)
+ */
+ private final int MAX_STARTER_COUNT = 3;
+
+ private ActivityStartController mController;
+ private ActivityManagerService mService;
+ private ActivityStackSupervisor mSupervisor;
+ private ActivityStartInterceptor mInterceptor;
+
+ private SynchronizedPool<ActivityStarter> mStarterPool =
+ new SynchronizedPool<>(MAX_STARTER_COUNT);
+
+ DefaultFactory(ActivityManagerService service,
+ ActivityStackSupervisor supervisor, ActivityStartInterceptor interceptor) {
+ mService = service;
+ mSupervisor = supervisor;
+ mInterceptor = interceptor;
+ }
+
+ @Override
+ public void setController(ActivityStartController controller) {
+ mController = controller;
+ }
+
+ @Override
+ public ActivityStarter obtain() {
+ ActivityStarter starter = mStarterPool.acquire();
+
+ if (starter == null) {
+ starter = new ActivityStarter(mController, mService, mSupervisor, mInterceptor);
+ }
+
+ return starter;
+ }
+
+ @Override
+ public void recycle(ActivityStarter starter) {
+ starter.reset(true /* clearRequest*/);
+ mStarterPool.release(starter);
+ }
+ }
+
+ /**
+ * 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;
+
+ /**
+ * Sets values back to the initial state, clearing any held references.
+ */
+ void reset() {
+ caller = null;
+ intent = null;
+ ephemeralIntent = null;
+ resolvedType = null;
+ activityInfo = null;
+ resolveInfo = null;
+ voiceSession = null;
+ voiceInteractor = null;
+ resultTo = null;
+ resultWho = null;
+ requestCode = 0;
+ callingPid = 0;
+ callingUid = 0;
+ callingPackage = null;
+ realCallingPid = 0;
+ realCallingUid = 0;
+ startFlags = 0;
+ activityOptions = null;
+ ignoreTargetSecurity = false;
+ componentSpecified = false;
+ outActivity = null;
+ inTask = null;
+ reason = null;
+ profilerInfo = null;
+ globalConfig = null;
+ waitOptions = null;
+ userId = 0;
+ waitResult = null;
+ mayWait = false;
+ }
+
+ /**
+ * Adopts all values from passed in request.
+ */
+ void set(Request request) {
+ caller = request.caller;
+ intent = request.intent;
+ ephemeralIntent = request.ephemeralIntent;
+ resolvedType = request.resolvedType;
+ activityInfo = request.activityInfo;
+ resolveInfo = request.resolveInfo;
+ voiceSession = request.voiceSession;
+ voiceInteractor = request.voiceInteractor;
+ resultTo = request.resultTo;
+ resultWho = request.resultWho;
+ requestCode = request.requestCode;
+ callingPid = request.callingPid;
+ callingUid = request.callingUid;
+ callingPackage = request.callingPackage;
+ realCallingPid = request.realCallingPid;
+ realCallingUid = request.realCallingUid;
+ startFlags = request.startFlags;
+ activityOptions = request.activityOptions;
+ ignoreTargetSecurity = request.ignoreTargetSecurity;
+ componentSpecified = request.componentSpecified;
+ outActivity = request.outActivity;
+ inTask = request.inTask;
+ reason = request.reason;
+ profilerInfo = request.profilerInfo;
+ globalConfig = request.globalConfig;
+ waitOptions = request.waitOptions;
+ userId = request.userId;
+ waitResult = request.waitResult;
+ mayWait = request.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;
+ reset(true);
}
- int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
+ /**
+ * Effectively duplicates the starter passed in. All state and request values will be
+ * mirrored.
+ * @param starter
+ */
+ void set(ActivityStarter starter) {
+ mStartActivity = starter.mStartActivity;
+ mIntent = starter.mIntent;
+ mCallingUid = starter.mCallingUid;
+ mOptions = starter.mOptions;
+
+ mLaunchTaskBehind = starter.mLaunchTaskBehind;
+ mLaunchFlags = starter.mLaunchFlags;
+ mLaunchMode = starter.mLaunchMode;
+
+ mLaunchBounds.set(starter.mLaunchBounds);
+
+ mNotTop = starter.mNotTop;
+ mDoResume = starter.mDoResume;
+ mStartFlags = starter.mStartFlags;
+ mSourceRecord = starter.mSourceRecord;
+ mPreferredDisplayId = starter.mPreferredDisplayId;
+
+ mInTask = starter.mInTask;
+ mAddingToTask = starter.mAddingToTask;
+ mReuseTask = starter.mReuseTask;
+
+ mNewTaskInfo = starter.mNewTaskInfo;
+ mNewTaskIntent = starter.mNewTaskIntent;
+ mSourceStack = starter.mSourceStack;
+
+ mTargetStack = starter.mTargetStack;
+ mMovedToFront = starter.mMovedToFront;
+ mNoAnimation = starter.mNoAnimation;
+ mKeepCurTransition = starter.mKeepCurTransition;
+ mAvoidMoveToFront = starter.mAvoidMoveToFront;
+
+ mVoiceSession = starter.mVoiceSession;
+ mVoiceInteractor = starter.mVoiceInteractor;
+
+ mIntentDelivered = starter.mIntentDelivered;
+
+ mRequest.set(starter.mRequest);
+ }
+
+ 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() {
+ try {
+ // 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);
+ }
+ } finally {
+ onExecutionComplete();
+ }
+ }
+
+ /**
+ * 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) {
+ try {
+ return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
+ doResume, options, inTask, outActivity);
+ } finally {
+ onExecutionComplete();
+ }
+ }
+
+ 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 +530,19 @@
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. */
+ /**
+ * Called when execution is complete. Sets state indicating completion and proceeds with
+ * recycling if appropriate.
+ */
+ private void onExecutionComplete() {
+ mController.onExecutionComplete(this);
+ }
+
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
@@ -536,9 +805,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 +823,10 @@
mService.mDidAppSwitch = true;
}
- doPendingActivityLaunchesLocked(false);
+ mController.doPendingActivityLaunches(false);
- return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
- options, inTask, outActivity);
+ return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
+ true /* doResume */, options, inTask, outActivity);
}
/**
@@ -578,11 +846,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 +874,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 +888,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 +1032,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 +1098,10 @@
}
}
- 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) {
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
+ ActivityRecord[] outActivity) {
int result = START_CANCELED;
try {
mService.mWindowManager.deferSurfaceLayout();
@@ -1076,7 +1199,7 @@
}
}
- sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, reusedActivity);
+ mSupervisor.sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, reusedActivity);
reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity);
@@ -1191,7 +1314,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);
@@ -1234,10 +1357,56 @@
return START_SUCCESS;
}
+ /**
+ * Resets the {@link ActivityStarter} state.
+ * @param clearRequest whether the request should be reset to default values.
+ */
+ void reset(boolean clearRequest) {
+ mStartActivity = null;
+ mIntent = null;
+ mCallingUid = -1;
+ mOptions = null;
+
+ mLaunchTaskBehind = false;
+ mLaunchFlags = 0;
+ mLaunchMode = INVALID_LAUNCH_MODE;
+
+ 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;
+
+ if (clearRequest) {
+ mRequest.reset();
+ }
+ }
+
private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
boolean doResume, int startFlags, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
- reset();
+ reset(false /* clearRequest */);
mStartActivity = r;
mIntent = r.intent;
@@ -1945,6 +2114,7 @@
return START_SUCCESS;
}
+ @VisibleForTesting
void updateBounds(TaskRecord task, Rect bounds) {
if (bounds.isEmpty()) {
return;
@@ -2008,20 +2178,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();
@@ -2178,35 +2334,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);
@@ -2225,15 +2503,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 ab86dbdb..f821f6b 100644
--- a/services/core/java/com/android/server/am/AppTaskImpl.java
+++ b/services/core/java/com/android/server/am/AppTaskImpl.java
@@ -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..93fb3e3 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);
@@ -1336,8 +1335,7 @@
null, mStats.mHandler, null, mUserManagerUserInfoProvider);
checkinStats.readSummaryFromParcel(in);
in.recycle();
- checkinStats.dumpProtoLocked(mContext, fd, apps, flags,
- historyStart);
+ checkinStats.dumpProtoLocked(mContext, fd, apps, flags);
mStats.mCheckinFile.delete();
return;
}
@@ -1350,7 +1348,7 @@
}
if (DBG) Slog.d(TAG, "begin dumpProtoLocked from UID " + Binder.getCallingUid());
synchronized (mStats) {
- mStats.dumpProtoLocked(mContext, fd, apps, flags, historyStart);
+ mStats.dumpProtoLocked(mContext, fd, apps, flags);
if (writeData) {
mStats.writeAsyncLocked();
}
diff --git a/services/core/java/com/android/server/am/ClientLifecycleManager.java b/services/core/java/com/android/server/am/ClientLifecycleManager.java
index c04d103..014f708 100644
--- a/services/core/java/com/android/server/am/ClientLifecycleManager.java
+++ b/services/core/java/com/android/server/am/ClientLifecycleManager.java
@@ -43,6 +43,8 @@
*/
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
transaction.schedule();
+ // TODO: b/70616950
+ //transaction.recycle();
}
/**
@@ -100,7 +102,7 @@
*/
private static ClientTransaction transactionWithState(@NonNull IApplicationThread client,
@NonNull IBinder activityToken, @NonNull ActivityLifecycleItem stateRequest) {
- final ClientTransaction clientTransaction = new ClientTransaction(client, activityToken);
+ final ClientTransaction clientTransaction = ClientTransaction.obtain(client, activityToken);
clientTransaction.setLifecycleStateRequest(stateRequest);
return clientTransaction;
}
@@ -113,7 +115,7 @@
*/
private static ClientTransaction transactionWithCallback(@NonNull IApplicationThread client,
IBinder activityToken, @NonNull ClientTransactionItem callback) {
- final ClientTransaction clientTransaction = new ClientTransaction(client, activityToken);
+ final ClientTransaction clientTransaction = ClientTransaction.obtain(client, activityToken);
clientTransaction.addCallback(callback);
return clientTransaction;
}
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/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 ebcf8c2..abb296e 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -502,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);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 83965ee..dabcbcd 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,
@@ -1632,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;
@@ -2320,4 +2064,387 @@
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 {
+ handleUnknownTag(name, 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;
+ }
+
+ void handleUnknownTag(String name, XmlPullParser in)
+ throws IOException, XmlPullParserException {
+ Slog.e(TAG, "restoreTask: Unexpected name=" + name);
+ XmlUtils.skipCurrentTag(in);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 4e3d8d2..14260c5 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="
@@ -919,6 +927,9 @@
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/DefaultNetworkMetrics.java b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
index 28c3585..bd2e96e 100644
--- a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
+++ b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
@@ -51,6 +51,7 @@
// Information about the current status of the default network.
@GuardedBy("this")
private DefaultNetworkEvent mCurrentDefaultNetwork;
+ // True if the current default network has been validated.
@GuardedBy("this")
private boolean mIsCurrentlyValid;
@GuardedBy("this")
@@ -71,6 +72,8 @@
printEvent(localTimeMs, pw, ev);
}
mCurrentDefaultNetwork.updateDuration(timeMs);
+ // When printing default network events for bug reports, update validation time
+ // and refresh the last validation timestmap for future validation time updates.
if (mIsCurrentlyValid) {
updateValidationTime(timeMs);
mLastValidationTimeMs = timeMs;
@@ -92,11 +95,13 @@
}
public synchronized void logDefaultNetworkValidity(long timeMs, boolean isValid) {
+ // Transition from valid to invalid: update validity duration since last update
if (!isValid && mIsCurrentlyValid) {
mIsCurrentlyValid = false;
updateValidationTime(timeMs);
}
+ // Transition from invalid to valid: simply mark the validation timestamp.
if (isValid && !mIsCurrentlyValid) {
mIsCurrentlyValid = true;
mLastValidationTimeMs = timeMs;
@@ -114,6 +119,9 @@
}
private void logCurrentDefaultNetwork(long timeMs, NetworkAgentInfo oldNai) {
+ if (mIsCurrentlyValid) {
+ updateValidationTime(timeMs);
+ }
DefaultNetworkEvent ev = mCurrentDefaultNetwork;
ev.updateDuration(timeMs);
ev.previousTransports = mLastTransports;
@@ -122,7 +130,6 @@
// The system acquired a new default network.
fillLinkInfo(ev, oldNai);
ev.finalScore = oldNai.getCurrentScore();
- ev.validatedMs = ev.durationMs;
}
// Only change transport of the previous default network if the event currently logged
// corresponds to an existing default network, and not to the absence of a default network.
@@ -143,9 +150,10 @@
fillLinkInfo(ev, newNai);
ev.initialScore = newNai.getCurrentScore();
if (newNai.lastValidated) {
- mIsCurrentlyValid = true;
- mLastValidationTimeMs = timeMs;
+ logDefaultNetworkValidity(timeMs, true);
}
+ } else {
+ mIsCurrentlyValid = false;
}
mCurrentDefaultNetwork = ev;
}
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/connectivity/OWNERS b/services/core/java/com/android/server/connectivity/OWNERS
index 74f39a1..6f77e04 100644
--- a/services/core/java/com/android/server/connectivity/OWNERS
+++ b/services/core/java/com/android/server/connectivity/OWNERS
@@ -2,4 +2,6 @@
ek@google.com
hugobenichi@google.com
+jchalard@google.com
lorenzo@google.com
+satk@google.com
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index c4e6ff6..6280edb 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -644,6 +644,11 @@
int userId = UserHandle.getCallingUserId();
final int callingUid = Binder.getCallingUid();
+ if (request.isPeriodic()) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
+ "no permission to write the sync settings");
+ }
+
long identityToken = clearCallingIdentity();
try {
SyncStorageEngine.EndPoint info;
@@ -653,8 +658,6 @@
info = new SyncStorageEngine.EndPoint(account, provider, userId);
if (request.isPeriodic()) {
// Remove periodic sync.
- mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
- "no permission to write the sync settings");
getSyncManager().removePeriodicSync(info, extras,
"cancelRequest() by uid=" + callingUid);
}
diff --git a/services/core/java/com/android/server/content/SyncJobService.java b/services/core/java/com/android/server/content/SyncJobService.java
index 07f04b1..29b322e 100644
--- a/services/core/java/com/android/server/content/SyncJobService.java
+++ b/services/core/java/com/android/server/content/SyncJobService.java
@@ -120,6 +120,7 @@
synchronized (jobParamsMap) {
JobParameters params = jobParamsMap.get(jobId);
mLogger.log("callJobFinished()",
+ " jobid=", jobId,
" needsReschedule=", needsReschedule,
" ", mLogger.jobParametersToString(params),
" why=", why);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 9cd52d7..965159b 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 */);
}
};
@@ -565,7 +565,7 @@
mLogger = SyncLogger.getInstance();
- SyncStorageEngine.init(context);
+ SyncStorageEngine.init(context, BackgroundThread.get().getLooper());
mSyncStorageEngine = SyncStorageEngine.getSingleton();
mSyncStorageEngine.setOnSyncRequestListener(new OnSyncRequestListener() {
@Override
@@ -735,15 +735,15 @@
}
public void onStartUser(int userHandle) {
- mLogger.log("onStartUser: user=", userHandle);
+ mSyncHandler.post(() -> mLogger.log("onStartUser: user=", userHandle));
}
public void onUnlockUser(int userHandle) {
- mLogger.log("onUnlockUser: user=", userHandle);
+ mSyncHandler.post(() -> mLogger.log("onUnlockUser: user=", userHandle));
}
public void onStopUser(int userHandle) {
- mLogger.log("onStopUser: user=", userHandle);
+ mSyncHandler.post(() -> mLogger.log("onStopUser: user=", userHandle));
}
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 3591871..e498666 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -36,6 +36,7 @@
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.RemoteCallbackList;
@@ -69,7 +70,7 @@
*
* @hide
*/
-public class SyncStorageEngine extends Handler {
+public class SyncStorageEngine {
private static final String TAG = "SyncManager";
private static final String TAG_FILE = "SyncManagerFile";
@@ -462,7 +463,10 @@
private boolean mGrantSyncAdaptersAccountAccess;
- private SyncStorageEngine(Context context, File dataDir) {
+ private final MyHandler mHandler;
+
+ private SyncStorageEngine(Context context, File dataDir, Looper looper) {
+ mHandler = new MyHandler(looper);
mContext = context;
sSyncStorageEngine = this;
@@ -491,15 +495,15 @@
}
public static SyncStorageEngine newTestInstance(Context context) {
- return new SyncStorageEngine(context, context.getFilesDir());
+ return new SyncStorageEngine(context, context.getFilesDir(), Looper.getMainLooper());
}
- public static void init(Context context) {
+ public static void init(Context context, Looper looper) {
if (sSyncStorageEngine != null) {
return;
}
File dataDir = Environment.getDataDirectory();
- sSyncStorageEngine = new SyncStorageEngine(context, dataDir);
+ sSyncStorageEngine = new SyncStorageEngine(context, dataDir, looper);
}
public static SyncStorageEngine getSingleton() {
@@ -527,14 +531,21 @@
}
}
- @Override public void handleMessage(Message msg) {
- if (msg.what == MSG_WRITE_STATUS) {
- synchronized (mAuthorities) {
- writeStatusLocked();
- }
- } else if (msg.what == MSG_WRITE_STATISTICS) {
- synchronized (mAuthorities) {
- writeStatisticsLocked();
+ private class MyHandler extends Handler {
+ public MyHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_WRITE_STATUS) {
+ synchronized (mAuthorities) {
+ writeStatusLocked();
+ }
+ } else if (msg.what == MSG_WRITE_STATISTICS) {
+ synchronized (mAuthorities) {
+ writeStatisticsLocked();
+ }
}
}
}
@@ -1202,14 +1213,14 @@
if (writeStatusNow) {
writeStatusLocked();
- } else if (!hasMessages(MSG_WRITE_STATUS)) {
- sendMessageDelayed(obtainMessage(MSG_WRITE_STATUS),
+ } else if (!mHandler.hasMessages(MSG_WRITE_STATUS)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_WRITE_STATUS),
WRITE_STATUS_DELAY);
}
if (writeStatisticsNow) {
writeStatisticsLocked();
- } else if (!hasMessages(MSG_WRITE_STATISTICS)) {
- sendMessageDelayed(obtainMessage(MSG_WRITE_STATISTICS),
+ } else if (!mHandler.hasMessages(MSG_WRITE_STATISTICS)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_WRITE_STATISTICS),
WRITE_STATISTICS_DELAY);
}
}
@@ -2102,7 +2113,7 @@
// The file is being written, so we don't need to have a scheduled
// write until the next change.
- removeMessages(MSG_WRITE_STATUS);
+ mHandler.removeMessages(MSG_WRITE_STATUS);
FileOutputStream fos = null;
try {
@@ -2210,7 +2221,7 @@
// The file is being written, so we don't need to have a scheduled
// write until the next change.
- removeMessages(MSG_WRITE_STATISTICS);
+ mHandler.removeMessages(MSG_WRITE_STATISTICS);
FileOutputStream fos = null;
try {
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 9a6e609..6c5bfc7 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -24,6 +24,7 @@
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.hardware.display.BrightnessConfiguration;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -34,7 +35,6 @@
import android.util.EventLog;
import android.util.MathUtils;
import android.util.Slog;
-import android.util.Spline;
import android.util.TimeUtils;
import java.io.PrintWriter;
@@ -76,9 +76,8 @@
// The light sensor, or null if not available or needed.
private final Sensor mLightSensor;
- // The auto-brightness spline adjustment.
- // The brightness values have been scaled to a range of 0..1.
- private final Spline mScreenAutoBrightnessSpline;
+ // The mapper to translate ambient lux to screen brightness in the range [0, 1.0].
+ private final BrightnessMappingStrategy mBrightnessMapper;
// The minimum and maximum screen brightnesses.
private final int mScreenBrightnessRangeMinimum;
@@ -186,7 +185,7 @@
private float mBrightnessAdjustmentSampleOldGamma;
public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
- SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
+ SensorManager sensorManager, BrightnessMappingStrategy mapper, int lightSensorWarmUpTime,
int brightnessMin, int brightnessMax, float dozeScaleFactor,
int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
@@ -194,7 +193,7 @@
HysteresisLevels dynamicHysteresis) {
mCallbacks = callbacks;
mSensorManager = sensorManager;
- mScreenAutoBrightnessSpline = autoBrightnessSpline;
+ mBrightnessMapper = mapper;
mScreenBrightnessRangeMinimum = brightnessMin;
mScreenBrightnessRangeMaximum = brightnessMax;
mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime;
@@ -228,15 +227,16 @@
return mScreenAutoBrightness;
}
- public void configure(boolean enable, float adjustment, boolean dozing,
- boolean userInitiatedChange) {
+ public void configure(boolean enable, @Nullable BrightnessConfiguration configuration,
+ float adjustment, boolean dozing, boolean userInitiatedChange) {
// While dozing, the application processor may be suspended which will prevent us from
// receiving new information from the light sensor. On some devices, we may be able to
// switch to a wake-up light sensor instead but for now we will simply disable the sensor
// and hold onto the last computed screen auto brightness. We save the dozing flag for
// debugging purposes.
mDozing = dozing;
- boolean changed = setLightSensorEnabled(enable && !dozing);
+ boolean changed = setBrightnessConfiguration(configuration);
+ changed |= setLightSensorEnabled(enable && !dozing);
if (enable && !dozing && userInitiatedChange) {
prepareBrightnessAdjustmentSample();
}
@@ -246,10 +246,13 @@
}
}
+ public boolean setBrightnessConfiguration(BrightnessConfiguration configuration) {
+ return mBrightnessMapper.setBrightnessConfiguration(configuration);
+ }
+
public void dump(PrintWriter pw) {
pw.println();
pw.println("Automatic Brightness Controller Configuration:");
- pw.println(" mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
pw.println(" mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
@@ -274,9 +277,13 @@
mInitialHorizonAmbientLightRingBuffer);
pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
pw.println(" mScreenAutoBrightnessAdjustment=" + mScreenAutoBrightnessAdjustment);
- pw.println(" mScreenAutoBrightnessAdjustmentMaxGamma=" + mScreenAutoBrightnessAdjustmentMaxGamma);
+ pw.println(" mScreenAutoBrightnessAdjustmentMaxGamma="
+ + mScreenAutoBrightnessAdjustmentMaxGamma);
pw.println(" mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
pw.println(" mDozing=" + mDozing);
+
+ pw.println();
+ mBrightnessMapper.dump(pw);
}
private boolean setLightSensorEnabled(boolean enable) {
@@ -533,7 +540,7 @@
return;
}
- float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
+ float value = mBrightnessMapper.getBrightness(mAmbientLux);
float gamma = 1.0f;
if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
new file mode 100644
index 0000000..3b9d40f
--- /dev/null
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -0,0 +1,289 @@
+/*
+ * 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.display;
+
+import android.annotation.Nullable;
+import android.hardware.display.BrightnessConfiguration;
+import android.os.PowerManager;
+import android.util.MathUtils;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.Spline;
+
+import com.android.internal.util.Preconditions;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.PrintWriter;
+
+/**
+ * A utility to map from an ambient brightness to a display's "backlight" brightness based on the
+ * available display information and brightness configuration.
+ *
+ * Note that without a mapping from the nits to a display backlight level, any
+ * {@link BrightnessConfiguration}s that are set are just ignored.
+ */
+public abstract class BrightnessMappingStrategy {
+ private static final String TAG = "BrightnessMappingStrategy";
+ private static final boolean DEBUG = false;
+
+ @Nullable
+ public static BrightnessMappingStrategy create(
+ float[] luxLevels, int[] brightnessLevelsBacklight, float[] brightnessLevelsNits,
+ float[] nitsRange, int[] backlightRange) {
+ if (isValidMapping(nitsRange, backlightRange)
+ && isValidMapping(luxLevels, brightnessLevelsNits)) {
+ BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
+ builder.setCurve(luxLevels, brightnessLevelsNits);
+ return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange);
+ } else if (isValidMapping(luxLevels, brightnessLevelsBacklight)) {
+ return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight);
+ } else {
+ return null;
+ }
+ }
+
+ private static boolean isValidMapping(float[] x, float[] y) {
+ if (x == null || y == null || x.length == 0 || y.length == 0) {
+ return false;
+ }
+ if (x.length != y.length) {
+ return false;
+ }
+ final int N = x.length;
+ float prevX = x[0];
+ float prevY = y[0];
+ if (prevX < 0 || prevY < 0 || Float.isNaN(prevX) || Float.isNaN(prevY)) {
+ return false;
+ }
+ for (int i = 1; i < N; i++) {
+ if (prevX >= x[i] || prevY > y[i]) {
+ return false;
+ }
+ if (Float.isNaN(x[i]) || Float.isNaN(y[i])) {
+ return false;
+ }
+ prevX = x[i];
+ prevY = y[i];
+ }
+ return true;
+ }
+
+ private static boolean isValidMapping(float[] x, int[] y) {
+ if (x == null || y == null || x.length == 0 || y.length == 0) {
+ return false;
+ }
+ if (x.length != y.length) {
+ return false;
+ }
+ final int N = x.length;
+ float prevX = x[0];
+ int prevY = y[0];
+ if (prevX < 0 || prevY < 0 || Float.isNaN(prevX)) {
+ return false;
+ }
+ for (int i = 1; i < N; i++) {
+ if (prevX >= x[i] || prevY > y[i]) {
+ return false;
+ }
+ if (Float.isNaN(x[i])) {
+ return false;
+ }
+ prevX = x[i];
+ prevY = y[i];
+ }
+ return true;
+ }
+
+ /**
+ * Sets the {@link BrightnessConfiguration}.
+ *
+ * @param config The new configuration. If {@code null} is passed, the default configuration is
+ * used.
+ * @return Whether the brightness configuration has changed.
+ */
+ public abstract boolean setBrightnessConfiguration(@Nullable BrightnessConfiguration config);
+
+ /**
+ * Returns the desired brightness of the display based on the current ambient lux.
+ *
+ * The returned brightness will be in the range [0, 1.0], where 1.0 is the display at max
+ * brightness and 0 is the display at minimum brightness.
+ *
+ * @param lux The current ambient brightness in lux.
+ * @return The desired brightness of the display compressed to the range [0, 1.0].
+ */
+ public abstract float getBrightness(float lux);
+
+ public abstract void dump(PrintWriter pw);
+
+ private static float normalizeAbsoluteBrightness(int brightness) {
+ brightness = MathUtils.constrain(brightness,
+ PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
+ return (float) brightness / PowerManager.BRIGHTNESS_ON;
+ }
+
+
+ /**
+ * A {@link BrightnessMappingStrategy} that maps from ambient room brightness directly to the
+ * backlight of the display.
+ *
+ * Since we don't have information about the display's physical brightness, any brightness
+ * configurations that are set are just ignored.
+ */
+ private static class SimpleMappingStrategy extends BrightnessMappingStrategy {
+ private final Spline mSpline;
+
+ public SimpleMappingStrategy(float[] lux, int[] brightness) {
+ Preconditions.checkArgument(lux.length != 0 && brightness.length != 0,
+ "Lux and brightness arrays must not be empty!");
+ Preconditions.checkArgument(lux.length == brightness.length,
+ "Lux and brightness arrays must be the same length!");
+ Preconditions.checkArrayElementsInRange(lux, 0, Float.MAX_VALUE, "lux");
+ Preconditions.checkArrayElementsInRange(brightness,
+ 0, Integer.MAX_VALUE, "brightness");
+
+ final int N = brightness.length;
+ float[] x = new float[N];
+ float[] y = new float[N];
+ for (int i = 0; i < N; i++) {
+ x[i] = lux[i];
+ y[i] = normalizeAbsoluteBrightness(brightness[i]);
+ }
+
+ mSpline = Spline.createSpline(x, y);
+ if (DEBUG) {
+ Slog.d(TAG, "Auto-brightness spline: " + mSpline);
+ for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
+ Slog.d(TAG, String.format(" %7.1f: %7.1f", v, mSpline.interpolate(v)));
+ }
+ }
+ }
+
+ @Override
+ public boolean setBrightnessConfiguration(@Nullable BrightnessConfiguration config) {
+ Slog.e(TAG,
+ "setBrightnessConfiguration called on device without display information.");
+ return false;
+ }
+
+ @Override
+ public float getBrightness(float lux) {
+ return mSpline.interpolate(lux);
+ }
+
+ @Override
+ public void dump(PrintWriter pw) {
+ pw.println("SimpleMappingStrategy");
+ pw.println(" mSpline=" + mSpline);
+ }
+ }
+
+ /** A {@link BrightnessMappingStrategy} that maps from ambient room brightness to the physical
+ * range of the display, rather than to the range of the backlight control (typically 0-255).
+ *
+ * By mapping through the physical brightness, the curve becomes portable across devices and
+ * gives us more resolution in the resulting mapping.
+ */
+ @VisibleForTesting
+ static class PhysicalMappingStrategy extends BrightnessMappingStrategy {
+ // The current brightness configuration.
+ private BrightnessConfiguration mConfig;
+
+ // A spline mapping from the current ambient light in lux to the desired display brightness
+ // in nits.
+ private Spline mBrightnessSpline;
+
+ // A spline mapping from nits to the corresponding backlight value, normalized to the range
+ // [0, 1.0].
+ private final Spline mBacklightSpline;
+
+ // The default brightness configuration.
+ private final BrightnessConfiguration mDefaultConfig;
+
+ public PhysicalMappingStrategy(BrightnessConfiguration config,
+ float[] nits, int[] backlight) {
+ Preconditions.checkArgument(nits.length != 0 && backlight.length != 0,
+ "Nits and backlight arrays must not be empty!");
+ Preconditions.checkArgument(nits.length == backlight.length,
+ "Nits and backlight arrays must be the same length!");
+ Preconditions.checkNotNull(config);
+ Preconditions.checkArrayElementsInRange(nits, 0, Float.MAX_VALUE, "nits");
+ Preconditions.checkArrayElementsInRange(backlight,
+ PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON, "backlight");
+
+ // Setup the backlight spline
+ final int N = nits.length;
+ float[] x = new float[N];
+ float[] y = new float[N];
+ for (int i = 0; i < N; i++) {
+ x[i] = nits[i];
+ y[i] = normalizeAbsoluteBrightness(backlight[i]);
+ }
+
+ mBacklightSpline = Spline.createSpline(x, y);
+ if (DEBUG) {
+ Slog.d(TAG, "Backlight spline: " + mBacklightSpline);
+ for (float v = 1f; v < nits[nits.length - 1] * 1.25f; v *= 1.25f) {
+ Slog.d(TAG, String.format(
+ " %7.1f: %7.1f", v, mBacklightSpline.interpolate(v)));
+ }
+ }
+
+ mDefaultConfig = config;
+ setBrightnessConfiguration(config);
+ }
+
+ @Override
+ public boolean setBrightnessConfiguration(@Nullable BrightnessConfiguration config) {
+ if (config == null) {
+ config = mDefaultConfig;
+ }
+ if (config.equals(mConfig)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Tried to set an identical brightness config, ignoring");
+ }
+ return false;
+ }
+
+ Pair<float[], float[]> curve = config.getCurve();
+ mBrightnessSpline = Spline.createSpline(curve.first /*lux*/, curve.second /*nits*/);
+ if (DEBUG) {
+ Slog.d(TAG, "Brightness spline: " + mBrightnessSpline);
+ final float[] lux = curve.first;
+ for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
+ Slog.d(TAG, String.format(
+ " %7.1f: %7.1f", v, mBrightnessSpline.interpolate(v)));
+ }
+ }
+ mConfig = config;
+ return true;
+ }
+
+ @Override
+ public float getBrightness(float lux) {
+ return mBacklightSpline.interpolate(mBrightnessSpline.interpolate(lux));
+ }
+
+ @Override
+ public void dump(PrintWriter pw) {
+ pw.println("PhysicalMappingStrategy");
+ pw.println(" mConfig=" + mConfig);
+ pw.println(" mBrightnessSpline=" + mBrightnessSpline);
+ pw.println(" mBacklightSpline=" + mBacklightSpline);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 90888f0..42247f9 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);
@@ -487,13 +500,30 @@
}
public void dump(PrintWriter pw) {
- synchronized (mEventsLock) {
- pw.println("BrightnessTracker state:");
- pw.println(" mEvents.size=" + mEvents.size());
- pw.println(" mEventsDirty=" + mEventsDirty);
- }
+ pw.println("BrightnessTracker state:");
synchronized (mDataCollectionLock) {
pw.println(" mLastSensorReadings.size=" + mLastSensorReadings.size());
+ if (!mLastSensorReadings.isEmpty()) {
+ pw.println(" mLastSensorReadings time span "
+ + mLastSensorReadings.peekFirst().timestamp + "->"
+ + mLastSensorReadings.peekLast().timestamp);
+ }
+ }
+ synchronized (mEventsLock) {
+ pw.println(" mEventsDirty=" + mEventsDirty);
+ pw.println(" mEvents.size=" + mEvents.size());
+ BrightnessChangeEvent[] events = mEvents.toArray();
+ for (int i = 0; i < events.length; ++i) {
+ pw.print(" " + events[i].timeStamp + ", " + events[i].userId);
+ pw.print(", " + events[i].lastBrightness + "->" + events[i].brightness + ", {");
+ for (int j = 0; j < events[i].luxValues.length; ++j){
+ if (j != 0) {
+ pw.print(", ");
+ }
+ pw.print("(" + events[i].luxValues[j] + "," + events[i].luxTimestamps[j] + ")");
+ }
+ pw.println("}");
+ }
}
}
@@ -584,6 +614,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 +626,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 +710,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..b3d309d 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;
@@ -231,7 +189,7 @@
mController = new ColorDisplayController(getContext(), mCurrentUser);
mController.setListener(this);
- setCoefficientMatrix(getContext());
+ setCoefficientMatrix(getContext(), DisplayTransformManager.isNativeModeEnabled());
// Prepare color transformation matrix.
setMatrix(mController.getColorTemperature(), mMatrixNight);
@@ -329,17 +287,24 @@
}
@Override
- public void onDisplayColorModeChanged(int colorMode) {
- final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
- dtm.setColorMode(colorMode);
+ public void onDisplayColorModeChanged(int mode) {
+ // Cancel the night display tint animator if it's running.
+ if (mColorMatrixAnimator != null) {
+ mColorMatrixAnimator.cancel();
+ }
- setCoefficientMatrix(getContext());
+ setCoefficientMatrix(getContext(), mode == ColorDisplayController.COLOR_MODE_SATURATED);
setMatrix(mController.getColorTemperature(), mMatrixNight);
- applyTint(true);
+
+ final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
+ dtm.setColorMode(mode, mIsActivated ? mMatrixNight : MATRIX_IDENTITY);
}
- private void setCoefficientMatrix(Context context) {
- final boolean isNative = DisplayTransformManager.isNativeModeEnabled();
+ /**
+ * Set coefficients based on native mode. Use DisplayTransformManager#isNativeModeEnabled while
+ * setting is stable; when setting is changing, pass native mode selection directly.
+ */
+ private void setCoefficientMatrix(Context context, boolean isNative) {
final String[] coefficients = context.getResources().getStringArray(isNative
? R.array.config_nightDisplayColorTemperatureCoefficientsNative
: R.array.config_nightDisplayColorTemperatureCoefficients);
@@ -359,11 +324,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..9b97934 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -29,6 +29,8 @@
import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
@@ -36,6 +38,7 @@
import android.graphics.Point;
import android.hardware.SensorManager;
import android.hardware.display.BrightnessChangeEvent;
+import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayViewport;
@@ -61,6 +64,7 @@
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
+import android.os.UserManager;
import android.text.TextUtils;
import android.util.IntArray;
import android.util.Slog;
@@ -69,12 +73,14 @@
import android.view.DisplayInfo;
import android.view.Surface;
+import com.android.internal.util.Preconditions;
import com.android.server.AnimationThread;
import com.android.server.DisplayThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.UiThread;
import com.android.server.wm.WindowManagerInternal;
+import com.android.server.wm.SurfaceAnimationThread;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -143,6 +149,7 @@
private static final int MSG_REQUEST_TRAVERSAL = 4;
private static final int MSG_UPDATE_VIEWPORT = 5;
private static final int MSG_REGISTER_BRIGHTNESS_TRACKER = 6;
+ private static final int MSG_LOAD_BRIGHTNESS_CONFIGURATION = 7;
private final Context mContext;
private final DisplayManagerHandler mHandler;
@@ -217,6 +224,9 @@
// The virtual display adapter, or null if not registered.
private VirtualDisplayAdapter mVirtualDisplayAdapter;
+ // The User ID of the current user
+ private @UserIdInt int mCurrentUserId;
+
// The stable device screen height and width. These are not tied to a specific display, even
// the default display, because they need to be stable over the course of the device's entire
// life, even if the default display changes (e.g. a new monitor is plugged into a PC-like
@@ -276,21 +286,24 @@
mDisplayAdapterListener = new DisplayAdapterListener();
mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
mDefaultDisplayDefaultColorMode = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_defaultDisplayDefaultColorMode);
+ com.android.internal.R.integer.config_defaultDisplayDefaultColorMode);
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
mBrightnessTracker = new BrightnessTracker(context, null);
+ mCurrentUserId = UserHandle.USER_SYSTEM;
}
public void setupSchedulerPolicies() {
// android.display and android.anim is critical to user experience and we should make sure
- // it is not in the default foregroup groups, add it to top-app to make sure it uses all the
- // cores and scheduling settings for top-app when it runs.
+ // it is not in the default foregroup groups, add it to top-app to make sure it uses all
+ // the cores and scheduling settings for top-app when it runs.
Process.setThreadGroupAndCpuset(DisplayThread.get().getThreadId(),
Process.THREAD_GROUP_TOP_APP);
Process.setThreadGroupAndCpuset(AnimationThread.get().getThreadId(),
Process.THREAD_GROUP_TOP_APP);
+ Process.setThreadGroupAndCpuset(SurfaceAnimationThread.get().getThreadId(),
+ Process.THREAD_GROUP_TOP_APP);
}
@Override
@@ -338,6 +351,19 @@
}
}
+ @Override
+ public void onSwitchUser(@UserIdInt int newUserId) {
+ final int userSerial = getUserManager().getUserSerialNumber(newUserId);
+ synchronized (mSyncRoot) {
+ if (mCurrentUserId != newUserId) {
+ mCurrentUserId = newUserId;
+ BrightnessConfiguration config =
+ mPersistentDataStore.getBrightnessConfiguration(userSerial);
+ mDisplayPowerController.setBrightnessConfiguration(config);
+ }
+ }
+ }
+
// TODO: Use dependencies or a boot phase
public void windowManagerAndInputReady() {
synchronized (mSyncRoot) {
@@ -981,6 +1007,30 @@
}
}
+ private void setBrightnessConfigurationForUserInternal(
+ @NonNull BrightnessConfiguration c, @UserIdInt int userId) {
+ final int userSerial = getUserManager().getUserSerialNumber(userId);
+ synchronized (mSyncRoot) {
+ try {
+ mPersistentDataStore.setBrightnessConfigurationForUser(c, userSerial);
+ } finally {
+ mPersistentDataStore.saveIfNeeded();
+ }
+ if (userId == mCurrentUserId) {
+ mDisplayPowerController.setBrightnessConfiguration(c);
+ }
+ }
+ }
+
+ private void loadBrightnessConfiguration() {
+ synchronized (mSyncRoot) {
+ final int userSerial = getUserManager().getUserSerialNumber(mCurrentUserId);
+ BrightnessConfiguration config =
+ mPersistentDataStore.getBrightnessConfiguration(userSerial);
+ mDisplayPowerController.setBrightnessConfiguration(config);
+ }
+ }
+
// Updates all existing logical displays given the current set of display devices.
// Removes invalid logical displays.
// Sends notifications if needed.
@@ -1225,6 +1275,10 @@
return mProjectionService;
}
+ private UserManager getUserManager() {
+ return mContext.getSystemService(UserManager.class);
+ }
+
private void dumpInternal(PrintWriter pw) {
pw.println("DISPLAY MANAGER (dumpsys display)");
@@ -1367,6 +1421,10 @@
case MSG_REGISTER_BRIGHTNESS_TRACKER:
mBrightnessTracker.start();
break;
+
+ case MSG_LOAD_BRIGHTNESS_CONFIGURATION:
+ loadBrightnessConfiguration();
+ break;
}
}
}
@@ -1752,14 +1810,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);
}
@@ -1780,6 +1854,27 @@
}
}
+ @Override // Binder call
+ public void setBrightnessConfigurationForUser(
+ BrightnessConfiguration c, @UserIdInt int userId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS,
+ "Permission required to change the display's brightness configuration");
+ if (userId != UserHandle.getCallingUserId()) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ "Permission required to change the display brightness"
+ + " configuration of another user");
+ }
+ Preconditions.checkNotNull(c);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ setBrightnessConfigurationForUserInternal(c, userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private boolean validatePackageName(int uid, String packageName) {
if (packageName != null) {
String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
@@ -1851,18 +1946,24 @@
mDisplayPowerController = new DisplayPowerController(
mContext, callbacks, handler, sensorManager, blanker);
}
+
+ mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATION);
}
@Override
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
- return mDisplayPowerController.requestPowerState(request,
- waitForNegativeProximity);
+ synchronized (mSyncRoot) {
+ return mDisplayPowerController.requestPowerState(request,
+ waitForNegativeProximity);
+ }
}
@Override
public boolean isProximitySensorAvailable() {
- return mDisplayPowerController.isProximitySensorAvailable();
+ synchronized (mSyncRoot) {
+ return mDisplayPowerController.isProximitySensorAvailable();
+ }
}
@Override
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 29a007a..a2d9548 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -26,10 +26,12 @@
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.os.Handler;
@@ -93,6 +95,8 @@
private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
private static final int MSG_SCREEN_ON_UNBLOCKED = 3;
private static final int MSG_SCREEN_OFF_UNBLOCKED = 4;
+ private static final int MSG_CONFIGURE_BRIGHTNESS = 5;
+ private static final int MSG_USER_SWITCH = 6;
private static final int PROXIMITY_UNKNOWN = -1;
private static final int PROXIMITY_NEGATIVE = 0;
@@ -285,6 +289,14 @@
// The controller for the automatic brightness level.
private AutomaticBrightnessController mAutomaticBrightnessController;
+ // The default brightness configuration. Used for whenever we don't have a valid brightness
+ // configuration set. This is typically seen with users that don't have a brightness
+ // configuration that's different from the default.
+ private BrightnessConfiguration mDefaultBrightnessConfiguration;
+
+ // The current brightness configuration.
+ private BrightnessConfiguration mBrightnessConfiguration;
+
// Animators.
private ObjectAnimator mColorFadeOnAnimator;
private ObjectAnimator mColorFadeOffAnimator;
@@ -333,7 +345,8 @@
screenBrightnessSettingMinimum, mScreenBrightnessDimConfig),
mScreenBrightnessDarkConfig);
- mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
+ mScreenBrightnessRangeMaximum = clampAbsoluteBrightness(resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessSettingMaximum));
mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);
@@ -348,60 +361,60 @@
mSkipScreenOnBrightnessRamp = resources.getBoolean(
com.android.internal.R.bool.config_skipScreenOnBrightnessRamp);
- int lightSensorRate = resources.getInteger(
- com.android.internal.R.integer.config_autoBrightnessLightSensorRate);
- int initialLightSensorRate = resources.getInteger(
- com.android.internal.R.integer.config_autoBrightnessInitialLightSensorRate);
- if (initialLightSensorRate == -1) {
- initialLightSensorRate = lightSensorRate;
- } else if (initialLightSensorRate > lightSensorRate) {
- Slog.w(TAG, "Expected config_autoBrightnessInitialLightSensorRate ("
- + initialLightSensorRate + ") to be less than or equal to "
- + "config_autoBrightnessLightSensorRate (" + lightSensorRate + ").");
- }
- long brighteningLightDebounce = resources.getInteger(
- com.android.internal.R.integer.config_autoBrightnessBrighteningLightDebounce);
- long darkeningLightDebounce = resources.getInteger(
- com.android.internal.R.integer.config_autoBrightnessDarkeningLightDebounce);
- boolean autoBrightnessResetAmbientLuxAfterWarmUp = resources.getBoolean(
- com.android.internal.R.bool.config_autoBrightnessResetAmbientLuxAfterWarmUp);
- int ambientLightHorizon = resources.getInteger(
- com.android.internal.R.integer.config_autoBrightnessAmbientLightHorizon);
- float autoBrightnessAdjustmentMaxGamma = resources.getFraction(
- com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma,
- 1, 1);
-
- int[] brightLevels = resources.getIntArray(
- com.android.internal.R.array.config_dynamicHysteresisBrightLevels);
- int[] darkLevels = resources.getIntArray(
- com.android.internal.R.array.config_dynamicHysteresisDarkLevels);
- int[] luxLevels = resources.getIntArray(
- com.android.internal.R.array.config_dynamicHysteresisLuxLevels);
- HysteresisLevels dynamicHysteresis = new HysteresisLevels(
- brightLevels, darkLevels, luxLevels);
-
if (mUseSoftwareAutoBrightnessConfig) {
- int[] lux = resources.getIntArray(
- com.android.internal.R.array.config_autoBrightnessLevels);
- int[] screenBrightness = resources.getIntArray(
+ float[] luxLevels = getLuxLevels(resources.getIntArray(
+ com.android.internal.R.array.config_autoBrightnessLevels));
+ int[] backlightValues = resources.getIntArray(
com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
- int lightSensorWarmUpTimeConfig = resources.getInteger(
- com.android.internal.R.integer.config_lightSensorWarmupTime);
+ float[] brightnessValuesNits = getFloatArray(resources.obtainTypedArray(
+ com.android.internal.R.array.config_autoBrightnessDisplayValuesNits));
+
+ final float screenMinimumNits = resources.getFloat(
+ com.android.internal.R.dimen.config_screenBrightnessMinimumNits);
+ final float screenMaximumNits = resources.getFloat(
+ com.android.internal.R.dimen.config_screenBrightnessMaximumNits);
+
final float dozeScaleFactor = resources.getFraction(
com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor,
1, 1);
- Spline screenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
- if (screenAutoBrightnessSpline == null) {
- Slog.e(TAG, "Error in config.xml. config_autoBrightnessLcdBacklightValues "
- + "(size " + screenBrightness.length + ") "
- + "must be monotic and have exactly one more entry than "
- + "config_autoBrightnessLevels (size " + lux.length + ") "
- + "which must be strictly increasing. "
- + "Auto-brightness will be disabled.");
- mUseSoftwareAutoBrightnessConfig = false;
- } else {
- int bottom = clampAbsoluteBrightness(screenBrightness[0]);
+ int[] brightLevels = resources.getIntArray(
+ com.android.internal.R.array.config_dynamicHysteresisBrightLevels);
+ int[] darkLevels = resources.getIntArray(
+ com.android.internal.R.array.config_dynamicHysteresisDarkLevels);
+ int[] luxHysteresisLevels = resources.getIntArray(
+ com.android.internal.R.array.config_dynamicHysteresisLuxLevels);
+ HysteresisLevels dynamicHysteresis = new HysteresisLevels(
+ brightLevels, darkLevels, luxHysteresisLevels);
+
+ long brighteningLightDebounce = resources.getInteger(
+ com.android.internal.R.integer.config_autoBrightnessBrighteningLightDebounce);
+ long darkeningLightDebounce = resources.getInteger(
+ com.android.internal.R.integer.config_autoBrightnessDarkeningLightDebounce);
+ boolean autoBrightnessResetAmbientLuxAfterWarmUp = resources.getBoolean(
+ com.android.internal.R.bool.config_autoBrightnessResetAmbientLuxAfterWarmUp);
+ int ambientLightHorizon = resources.getInteger(
+ com.android.internal.R.integer.config_autoBrightnessAmbientLightHorizon);
+ float autoBrightnessAdjustmentMaxGamma = resources.getFraction(
+ com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma,
+ 1, 1);
+
+ int lightSensorWarmUpTimeConfig = resources.getInteger(
+ com.android.internal.R.integer.config_lightSensorWarmupTime);
+ int lightSensorRate = resources.getInteger(
+ com.android.internal.R.integer.config_autoBrightnessLightSensorRate);
+ int initialLightSensorRate = resources.getInteger(
+ com.android.internal.R.integer.config_autoBrightnessInitialLightSensorRate);
+ if (initialLightSensorRate == -1) {
+ initialLightSensorRate = lightSensorRate;
+ } else if (initialLightSensorRate > lightSensorRate) {
+ Slog.w(TAG, "Expected config_autoBrightnessInitialLightSensorRate ("
+ + initialLightSensorRate + ") to be less than or equal to "
+ + "config_autoBrightnessLightSensorRate (" + lightSensorRate + ").");
+ }
+
+ if (backlightValues != null && backlightValues.length > 0) {
+ final int bottom = backlightValues[0];
if (mScreenBrightnessDarkConfig > bottom) {
Slog.w(TAG, "config_screenBrightnessDark (" + mScreenBrightnessDarkConfig
+ ") should be less than or equal to the first value of "
@@ -411,13 +424,24 @@
if (bottom < screenBrightnessRangeMinimum) {
screenBrightnessRangeMinimum = bottom;
}
+ }
+
+ float[] nitsRange = { screenMinimumNits, screenMaximumNits };
+ int[] backlightRange = { screenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum };
+
+ BrightnessMappingStrategy mapper = BrightnessMappingStrategy.create(
+ luxLevels, backlightValues, brightnessValuesNits,
+ nitsRange, backlightRange);
+ if (mapper != null) {
mAutomaticBrightnessController = new AutomaticBrightnessController(this,
- handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
- lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
- mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
- initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
+ handler.getLooper(), sensorManager, mapper, lightSensorWarmUpTimeConfig,
+ screenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum,
+ dozeScaleFactor, lightSensorRate, initialLightSensorRate,
+ brighteningLightDebounce, darkeningLightDebounce,
autoBrightnessResetAmbientLuxAfterWarmUp, ambientLightHorizon,
autoBrightnessAdjustmentMaxGamma, dynamicHysteresis);
+ } else {
+ mUseSoftwareAutoBrightnessConfig = false;
}
}
@@ -444,6 +468,25 @@
}
+ private static float[] getLuxLevels(int[] lux) {
+ // The first control point is implicit and always at 0 lux.
+ float[] levels = new float[lux.length + 1];
+ for (int i = 0; i < lux.length; i++) {
+ levels[i + 1] = (float) lux[i];
+ }
+ return levels;
+ }
+
+ private static float[] getFloatArray(TypedArray array) {
+ final int N = array.length();
+ float[] vals = new float[N];
+ for (int i = 0; i < N; i++) {
+ vals[i] = array.getFloat(i, -1.0f);
+ }
+ array.recycle();
+ return vals;
+ }
+
/**
* Returns true if the proximity sensor screen-off function is available.
*/
@@ -512,7 +555,6 @@
if (!mPendingUpdatePowerStateLocked) {
mPendingUpdatePowerStateLocked = true;
Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
- msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
@@ -691,8 +733,8 @@
final boolean userInitiatedChange = autoBrightnessAdjustmentChanged
&& mPowerRequest.brightnessSetByUser;
mAutomaticBrightnessController.configure(autoBrightnessEnabled,
- mPowerRequest.screenAutoBrightnessAdjustment, state != Display.STATE_ON,
- userInitiatedChange);
+ mBrightnessConfiguration, mPowerRequest.screenAutoBrightnessAdjustment,
+ state != Display.STATE_ON, userInitiatedChange);
}
// Apply brightness boost.
@@ -874,6 +916,11 @@
sendUpdatePowerState();
}
+ public void setBrightnessConfiguration(BrightnessConfiguration c) {
+ Message msg = mHandler.obtainMessage(MSG_CONFIGURE_BRIGHTNESS, c);
+ msg.sendToTarget();
+ }
+
private void blockScreenOn() {
if (mPendingScreenOnUnblocker == null) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
@@ -1241,7 +1288,6 @@
// Need to wait a little longer.
// Debounce again later. We continue holding a wake lock while waiting.
Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
- msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
}
}
@@ -1402,39 +1448,6 @@
}
}
- private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
- if (lux == null || lux.length == 0 || brightness == null || brightness.length == 0) {
- Slog.e(TAG, "Could not create auto-brightness spline.");
- return null;
- }
- try {
- final int n = brightness.length;
- float[] x = new float[n];
- float[] y = new float[n];
- y[0] = normalizeAbsoluteBrightness(brightness[0]);
- for (int i = 1; i < n; i++) {
- x[i] = lux[i - 1];
- y[i] = normalizeAbsoluteBrightness(brightness[i]);
- }
-
- Spline spline = Spline.createSpline(x, y);
- if (DEBUG) {
- Slog.d(TAG, "Auto-brightness spline: " + spline);
- for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
- Slog.d(TAG, String.format(" %7.1f: %7.1f", v, spline.interpolate(v)));
- }
- }
- return spline;
- } catch (IllegalArgumentException ex) {
- Slog.e(TAG, "Could not create auto-brightness spline.", ex);
- return null;
- }
- }
-
- private static float normalizeAbsoluteBrightness(int value) {
- return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
- }
-
private static int clampAbsoluteBrightness(int value) {
return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
}
@@ -1467,6 +1480,11 @@
updatePowerState();
}
break;
+ case MSG_CONFIGURE_BRIGHTNESS:
+ BrightnessConfiguration c = (BrightnessConfiguration) msg.obj;
+ mBrightnessConfiguration = c != null ? c : mDefaultBrightnessConfiguration;
+ updatePowerState();
+ break;
}
}
}
@@ -1492,17 +1510,14 @@
@Override
public void onScreenOn() {
Message msg = mHandler.obtainMessage(MSG_SCREEN_ON_UNBLOCKED, this);
- msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
private final class ScreenOffUnblocker implements WindowManagerPolicy.ScreenOffListener {
-
@Override
public void onScreenOff() {
Message msg = mHandler.obtainMessage(MSG_SCREEN_OFF_UNBLOCKED, this);
- msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java
index 338e331..000fcf3 100644
--- a/services/core/java/com/android/server/display/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/DisplayTransformManager.java
@@ -222,7 +222,7 @@
return SystemProperties.getBoolean(PERSISTENT_PROPERTY_NATIVE_MODE, false);
}
- public boolean setColorMode(int colorMode) {
+ public boolean setColorMode(int colorMode, float[] nightDisplayMatrix) {
if (colorMode == ColorDisplayController.COLOR_MODE_NATURAL) {
applySaturation(COLOR_SATURATION_NATURAL);
setNativeMode(false);
@@ -233,6 +233,7 @@
applySaturation(COLOR_SATURATION_NATURAL);
setNativeMode(true);
}
+ setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, nightDisplayMatrix);
updateConfiguration();
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index 34c8e22..49b4465 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -24,12 +24,17 @@
import org.xmlpull.v1.XmlSerializer;
import android.graphics.Point;
+import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.WifiDisplay;
import android.util.AtomicFile;
import android.util.Slog;
+import android.util.SparseArray;
+import android.util.Pair;
import android.util.Xml;
import android.view.Display;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
@@ -37,10 +42,12 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import libcore.io.IoUtils;
@@ -57,14 +64,22 @@
* <wifi-display deviceAddress="00:00:00:00:00:00" deviceName="XXXX" deviceAlias="YYYY" />
* <remembered-wifi-displays>
* <display-states>
- * <display>
+ * <display unique-id="XXXXXXX">
* <color-mode>0</color-mode>
* </display>
* </display-states>
* <stable-device-values>
- * <stable-display-height>1920<stable-display-height>
- * <stable-display-width>1080<stable-display-width>
+ * <stable-display-height>1920</stable-display-height>
+ * <stable-display-width>1080</stable-display-width>
* </stable-device-values>
+ * <brightness-configurations>
+ * <brightness-configuration user-id="0">
+ * <brightness-curve>
+ * <brightness-point lux="0" nits="13.25"/>
+ * <brightness-point lux="20" nits="35.94"/>
+ * </brightness-curve>
+ * </brightness-configuration>
+ * </brightness-configurations>
* </display-manager-state>
* </code>
*
@@ -73,6 +88,31 @@
final class PersistentDataStore {
static final String TAG = "DisplayManager";
+ private static final String TAG_DISPLAY_MANAGER_STATE = "display-manager-state";
+
+ private static final String TAG_REMEMBERED_WIFI_DISPLAYS = "remembered-wifi-displays";
+ private static final String TAG_WIFI_DISPLAY = "wifi-display";
+ private static final String ATTR_DEVICE_ADDRESS = "deviceAddress";
+ private static final String ATTR_DEVICE_NAME = "deviceName";
+ private static final String ATTR_DEVICE_ALIAS = "deviceAlias";
+
+ private static final String TAG_DISPLAY_STATES = "display-states";
+ private static final String TAG_DISPLAY = "display";
+ private static final String TAG_COLOR_MODE = "color-mode";
+ private static final String ATTR_UNIQUE_ID = "unique-id";
+
+ private static final String TAG_STABLE_DEVICE_VALUES = "stable-device-values";
+ private static final String TAG_STABLE_DISPLAY_HEIGHT = "stable-display-height";
+ private static final String TAG_STABLE_DISPLAY_WIDTH = "stable-display-width";
+
+ private static final String TAG_BRIGHTNESS_CONFIGURATIONS = "brightness-configurations";
+ private static final String TAG_BRIGHTNESS_CONFIGURATION = "brightness-configuration";
+ private static final String TAG_BRIGHTNESS_CURVE = "brightness-curve";
+ private static final String TAG_BRIGHTNESS_POINT = "brightness-point";
+ private static final String ATTR_USER_SERIAL = "user-serial";
+ private static final String ATTR_LUX = "lux";
+ private static final String ATTR_NITS = "nits";
+
// Remembered Wifi display devices.
private ArrayList<WifiDisplay> mRememberedWifiDisplays = new ArrayList<WifiDisplay>();
@@ -83,8 +123,8 @@
// Display values which should be stable across the device's lifetime.
private final StableDeviceValues mStableDeviceValues = new StableDeviceValues();
- // The atomic file used to safely read or write the file.
- private final AtomicFile mAtomicFile;
+ // Brightness configuration by user
+ private BrightnessConfigurations mBrightnessConfigurations = new BrightnessConfigurations();
// True if the data has been loaded.
private boolean mLoaded;
@@ -92,8 +132,16 @@
// True if there are changes to be saved.
private boolean mDirty;
+ // The interface for methods which should be replaced by the test harness.
+ private Injector mInjector;
+
public PersistentDataStore() {
- mAtomicFile = new AtomicFile(new File("/data/system/display-manager-state.xml"));
+ this(new Injector());
+ }
+
+ @VisibleForTesting
+ PersistentDataStore(Injector injector) {
+ mInjector = injector;
}
public void saveIfNeeded() {
@@ -225,6 +273,18 @@
}
}
+ public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userSerial) {
+ loadIfNeeded();
+ if (mBrightnessConfigurations.setBrightnessConfigurationForUser(c, userSerial)) {
+ setDirty();
+ }
+ }
+
+ public BrightnessConfiguration getBrightnessConfiguration(int userSerial) {
+ loadIfNeeded();
+ return mBrightnessConfigurations.getBrightnessConfiguration(userSerial);
+ }
+
private DisplayState getDisplayState(String uniqueId, boolean createIfAbsent) {
loadIfNeeded();
DisplayState state = mDisplayStates.get(uniqueId);
@@ -256,7 +316,7 @@
final InputStream is;
try {
- is = mAtomicFile.openRead();
+ is = mInjector.openRead();
} catch (FileNotFoundException ex) {
return;
}
@@ -278,9 +338,9 @@
}
private void save() {
- final FileOutputStream os;
+ final OutputStream os;
try {
- os = mAtomicFile.startWrite();
+ os = mInjector.startWrite();
boolean success = false;
try {
XmlSerializer serializer = new FastXmlSerializer();
@@ -289,11 +349,7 @@
serializer.flush();
success = true;
} finally {
- if (success) {
- mAtomicFile.finishWrite(os);
- } else {
- mAtomicFile.failWrite(os);
- }
+ mInjector.finishWrite(os, success);
}
} catch (IOException ex) {
Slog.w(TAG, "Failed to save display manager persistent store data.", ex);
@@ -302,18 +358,21 @@
private void loadFromXml(XmlPullParser parser)
throws IOException, XmlPullParserException {
- XmlUtils.beginDocument(parser, "display-manager-state");
+ XmlUtils.beginDocument(parser, TAG_DISPLAY_MANAGER_STATE);
final int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
- if (parser.getName().equals("remembered-wifi-displays")) {
+ if (parser.getName().equals(TAG_REMEMBERED_WIFI_DISPLAYS)) {
loadRememberedWifiDisplaysFromXml(parser);
}
- if (parser.getName().equals("display-states")) {
+ if (parser.getName().equals(TAG_DISPLAY_STATES)) {
loadDisplaysFromXml(parser);
}
- if (parser.getName().equals("stable-device-values")) {
+ if (parser.getName().equals(TAG_STABLE_DEVICE_VALUES)) {
mStableDeviceValues.loadFromXml(parser);
}
+ if (parser.getName().equals(TAG_BRIGHTNESS_CONFIGURATIONS)) {
+ mBrightnessConfigurations.loadFromXml(parser);
+ }
}
}
@@ -321,10 +380,10 @@
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
- if (parser.getName().equals("wifi-display")) {
- String deviceAddress = parser.getAttributeValue(null, "deviceAddress");
- String deviceName = parser.getAttributeValue(null, "deviceName");
- String deviceAlias = parser.getAttributeValue(null, "deviceAlias");
+ if (parser.getName().equals(TAG_WIFI_DISPLAY)) {
+ String deviceAddress = parser.getAttributeValue(null, ATTR_DEVICE_ADDRESS);
+ String deviceName = parser.getAttributeValue(null, ATTR_DEVICE_NAME);
+ String deviceAlias = parser.getAttributeValue(null, ATTR_DEVICE_ALIAS);
if (deviceAddress == null || deviceName == null) {
throw new XmlPullParserException(
"Missing deviceAddress or deviceName attribute on wifi-display.");
@@ -345,8 +404,8 @@
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
- if (parser.getName().equals("display")) {
- String uniqueId = parser.getAttributeValue(null, "unique-id");
+ if (parser.getName().equals(TAG_DISPLAY)) {
+ String uniqueId = parser.getAttributeValue(null, ATTR_UNIQUE_ID);
if (uniqueId == null) {
throw new XmlPullParserException(
"Missing unique-id attribute on display.");
@@ -365,32 +424,35 @@
private void saveToXml(XmlSerializer serializer) throws IOException {
serializer.startDocument(null, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
- serializer.startTag(null, "display-manager-state");
- serializer.startTag(null, "remembered-wifi-displays");
+ serializer.startTag(null, TAG_DISPLAY_MANAGER_STATE);
+ serializer.startTag(null, TAG_REMEMBERED_WIFI_DISPLAYS);
for (WifiDisplay display : mRememberedWifiDisplays) {
- serializer.startTag(null, "wifi-display");
- serializer.attribute(null, "deviceAddress", display.getDeviceAddress());
- serializer.attribute(null, "deviceName", display.getDeviceName());
+ serializer.startTag(null, TAG_WIFI_DISPLAY);
+ serializer.attribute(null, ATTR_DEVICE_ADDRESS, display.getDeviceAddress());
+ serializer.attribute(null, ATTR_DEVICE_NAME, display.getDeviceName());
if (display.getDeviceAlias() != null) {
- serializer.attribute(null, "deviceAlias", display.getDeviceAlias());
+ serializer.attribute(null, ATTR_DEVICE_ALIAS, display.getDeviceAlias());
}
- serializer.endTag(null, "wifi-display");
+ serializer.endTag(null, TAG_WIFI_DISPLAY);
}
- serializer.endTag(null, "remembered-wifi-displays");
- serializer.startTag(null, "display-states");
+ serializer.endTag(null, TAG_REMEMBERED_WIFI_DISPLAYS);
+ serializer.startTag(null, TAG_DISPLAY_STATES);
for (Map.Entry<String, DisplayState> entry : mDisplayStates.entrySet()) {
final String uniqueId = entry.getKey();
final DisplayState state = entry.getValue();
- serializer.startTag(null, "display");
- serializer.attribute(null, "unique-id", uniqueId);
+ serializer.startTag(null, TAG_DISPLAY);
+ serializer.attribute(null, ATTR_UNIQUE_ID, uniqueId);
state.saveToXml(serializer);
- serializer.endTag(null, "display");
+ serializer.endTag(null, TAG_DISPLAY);
}
- serializer.endTag(null, "display-states");
- serializer.startTag(null, "stable-device-values");
+ serializer.endTag(null, TAG_DISPLAY_STATES);
+ serializer.startTag(null, TAG_STABLE_DEVICE_VALUES);
mStableDeviceValues.saveToXml(serializer);
- serializer.endTag(null, "stable-device-values");
- serializer.endTag(null, "display-manager-state");
+ serializer.endTag(null, TAG_STABLE_DEVICE_VALUES);
+ serializer.startTag(null, TAG_BRIGHTNESS_CONFIGURATIONS);
+ mBrightnessConfigurations.saveToXml(serializer);
+ serializer.endTag(null, TAG_BRIGHTNESS_CONFIGURATIONS);
+ serializer.endTag(null, TAG_DISPLAY_MANAGER_STATE);
serializer.endDocument();
}
@@ -411,6 +473,8 @@
}
pw.println(" StableDeviceValues:");
mStableDeviceValues.dump(pw, " ");
+ pw.println(" BrightnessConfigurations:");
+ mBrightnessConfigurations.dump(pw, " ");
}
private static final class DisplayState {
@@ -433,7 +497,7 @@
final int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
- if (parser.getName().equals("color-mode")) {
+ if (parser.getName().equals(TAG_COLOR_MODE)) {
String value = parser.nextText();
mColorMode = Integer.parseInt(value);
}
@@ -441,9 +505,9 @@
}
public void saveToXml(XmlSerializer serializer) throws IOException {
- serializer.startTag(null, "color-mode");
+ serializer.startTag(null, TAG_COLOR_MODE);
serializer.text(Integer.toString(mColorMode));
- serializer.endTag(null, "color-mode");
+ serializer.endTag(null, TAG_COLOR_MODE);
}
public void dump(final PrintWriter pw, final String prefix) {
@@ -472,10 +536,10 @@
final int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
switch (parser.getName()) {
- case "stable-display-width":
+ case TAG_STABLE_DISPLAY_WIDTH:
mWidth = loadIntValue(parser);
break;
- case "stable-display-height":
+ case TAG_STABLE_DISPLAY_HEIGHT:
mHeight = loadIntValue(parser);
break;
}
@@ -494,12 +558,12 @@
public void saveToXml(XmlSerializer serializer) throws IOException {
if (mWidth > 0 && mHeight > 0) {
- serializer.startTag(null, "stable-display-width");
+ serializer.startTag(null, TAG_STABLE_DISPLAY_WIDTH);
serializer.text(Integer.toString(mWidth));
- serializer.endTag(null, "stable-display-width");
- serializer.startTag(null, "stable-display-height");
+ serializer.endTag(null, TAG_STABLE_DISPLAY_WIDTH);
+ serializer.startTag(null, TAG_STABLE_DISPLAY_HEIGHT);
serializer.text(Integer.toString(mHeight));
- serializer.endTag(null, "stable-display-height");
+ serializer.endTag(null, TAG_STABLE_DISPLAY_HEIGHT);
}
}
@@ -508,4 +572,158 @@
pw.println(prefix + "StableDisplayHeight=" + mHeight);
}
}
+
+ private static final class BrightnessConfigurations {
+ // Maps from a user ID to the users' given brightness configuration
+ private SparseArray<BrightnessConfiguration> mConfigurations;
+
+ public BrightnessConfigurations() {
+ mConfigurations = new SparseArray<>();
+ }
+
+ private boolean setBrightnessConfigurationForUser(BrightnessConfiguration c,
+ int userSerial) {
+ BrightnessConfiguration currentConfig = mConfigurations.get(userSerial);
+ if (currentConfig == null || !currentConfig.equals(c)) {
+ mConfigurations.put(userSerial, c);
+ return true;
+ }
+ return false;
+ }
+
+ public BrightnessConfiguration getBrightnessConfiguration(int userSerial) {
+ return mConfigurations.get(userSerial);
+ }
+
+ public void loadFromXml(XmlPullParser parser) throws IOException, XmlPullParserException {
+ final int outerDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (TAG_BRIGHTNESS_CONFIGURATION.equals(parser.getName())) {
+ int userSerial;
+ try {
+ userSerial = Integer.parseInt(
+ parser.getAttributeValue(null, ATTR_USER_SERIAL));
+ } catch (NumberFormatException nfe) {
+ userSerial= -1;
+ Slog.e(TAG, "Failed to read in brightness configuration", nfe);
+ }
+
+ try {
+ BrightnessConfiguration config = loadConfigurationFromXml(parser);
+ if (userSerial>= 0 && config != null) {
+ mConfigurations.put(userSerial, config);
+ }
+ } catch (IllegalArgumentException iae) {
+ Slog.e(TAG, "Failed to load brightness configuration!", iae);
+ }
+ }
+ }
+ }
+
+ private static BrightnessConfiguration loadConfigurationFromXml(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ final int outerDepth = parser.getDepth();
+ final BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (TAG_BRIGHTNESS_CURVE.equals(parser.getName())) {
+ Pair<float[], float[]> curve = loadCurveFromXml(parser, builder);
+ builder.setCurve(curve.first /*lux*/, curve.second /*nits*/);
+ }
+ }
+ return builder.build();
+ }
+
+ private static Pair<float[], float[]> loadCurveFromXml(XmlPullParser parser,
+ BrightnessConfiguration.Builder builder)
+ throws IOException, XmlPullParserException {
+ final int outerDepth = parser.getDepth();
+ List<Float> luxLevels = new ArrayList<>();
+ List<Float> nitLevels = new ArrayList<>();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (TAG_BRIGHTNESS_POINT.equals(parser.getName())) {
+ luxLevels.add(loadFloat(parser.getAttributeValue(null, ATTR_LUX)));
+ nitLevels.add(loadFloat(parser.getAttributeValue(null, ATTR_NITS)));
+ }
+ }
+ final int N = luxLevels.size();
+ float[] lux = new float[N];
+ float[] nits = new float[N];
+ for (int i = 0; i < N; i++) {
+ lux[i] = luxLevels.get(i);
+ nits[i] = nitLevels.get(i);
+ }
+ return Pair.create(lux, nits);
+ }
+
+ private static float loadFloat(String val) {
+ try {
+ return Float.parseFloat(val);
+ } catch (NullPointerException | NumberFormatException e) {
+ Slog.e(TAG, "Failed to parse float loading brightness config", e);
+ return Float.NEGATIVE_INFINITY;
+ }
+ }
+
+ public void saveToXml(XmlSerializer serializer) throws IOException {
+ for (int i = 0; i < mConfigurations.size(); i++) {
+ final int userSerial= mConfigurations.keyAt(i);
+ final BrightnessConfiguration config = mConfigurations.valueAt(i);
+
+ serializer.startTag(null, TAG_BRIGHTNESS_CONFIGURATION);
+ serializer.attribute(null, ATTR_USER_SERIAL, Integer.toString(userSerial));
+ saveConfigurationToXml(serializer, config);
+ serializer.endTag(null, TAG_BRIGHTNESS_CONFIGURATION);
+ }
+ }
+
+ private static void saveConfigurationToXml(XmlSerializer serializer,
+ BrightnessConfiguration config) throws IOException {
+ serializer.startTag(null, TAG_BRIGHTNESS_CURVE);
+ final Pair<float[], float[]> curve = config.getCurve();
+ for (int i = 0; i < curve.first.length; i++) {
+ serializer.startTag(null, TAG_BRIGHTNESS_POINT);
+ serializer.attribute(null, ATTR_LUX, Float.toString(curve.first[i]));
+ serializer.attribute(null, ATTR_NITS, Float.toString(curve.second[i]));
+ serializer.endTag(null, TAG_BRIGHTNESS_POINT);
+ }
+ serializer.endTag(null, TAG_BRIGHTNESS_CURVE);
+ }
+
+ public void dump(final PrintWriter pw, final String prefix) {
+ for (int i = 0; i < mConfigurations.size(); i++) {
+ final int userSerial= mConfigurations.keyAt(i);
+ pw.println(prefix + "User " + userSerial + ":");
+ pw.println(prefix + " " + mConfigurations.valueAt(i));
+ }
+ }
+ }
+
+ @VisibleForTesting
+ static class Injector {
+ private final AtomicFile mAtomicFile;
+
+ public Injector() {
+ mAtomicFile = new AtomicFile(new File("/data/system/display-manager-state.xml"));
+ }
+
+ public InputStream openRead() throws FileNotFoundException {
+ return mAtomicFile.openRead();
+ }
+
+ public OutputStream startWrite() throws IOException {
+ return mAtomicFile.startWrite();
+ }
+
+ public void finishWrite(OutputStream os, boolean success) {
+ if (!(os instanceof FileOutputStream)) {
+ throw new IllegalArgumentException("Unexpected OutputStream as argument: " + os);
+ }
+ FileOutputStream fos = (FileOutputStream) os;
+ if (success) {
+ mAtomicFile.finishWrite(fos);
+ } else {
+ mAtomicFile.failWrite(fos);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/dreams/OWNERS b/services/core/java/com/android/server/dreams/OWNERS
new file mode 100644
index 0000000..3c9bbf8
--- /dev/null
+++ b/services/core/java/com/android/server/dreams/OWNERS
@@ -0,0 +1,3 @@
+dsandler@google.com
+michaelwr@google.com
+roosa@google.com
diff --git a/services/core/java/com/android/server/job/JobSchedulerInternal.java b/services/core/java/com/android/server/job/JobSchedulerInternal.java
index 9bcf208..c97eeaf 100644
--- a/services/core/java/com/android/server/job/JobSchedulerInternal.java
+++ b/services/core/java/com/android/server/job/JobSchedulerInternal.java
@@ -44,6 +44,11 @@
List<JobInfo> getSystemScheduledPendingJobs();
/**
+ * Cancel the jobs for a given uid (e.g. when app data is cleared)
+ */
+ void cancelJobsForUid(int uid, String reason);
+
+ /**
* These are for activity manager to communicate to use what is currently performing backups.
*/
void addBackingUpUid(int uid);
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 4af86a0..009f10e7 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;
@@ -1721,16 +1721,29 @@
// If the app is in a non-active standby bucket, make sure we've waited
// an appropriate amount of time since the last invocation
- if (mHeartbeat < mNextBucketHeartbeat[job.getStandbyBucket()]) {
- // TODO: log/trace that we're deferring the job due to bucketing if we hit this
- if (job.getWhenStandbyDeferred() == 0) {
- if (DEBUG_STANDBY) {
- Slog.v(TAG, "Bucket deferral: " + mHeartbeat + " < "
- + mNextBucketHeartbeat[job.getStandbyBucket()] + " for " + job);
+ final int bucket = job.getStandbyBucket();
+ if (mHeartbeat < mNextBucketHeartbeat[bucket]) {
+ // Only skip this job if it's still waiting for the end of its (initial) nominal
+ // bucket interval. Once it's waited that long, we let it go ahead and clear.
+ // The final (NEVER) bucket is special; we never age those apps' jobs into
+ // runnability.
+ if (bucket >= mConstants.STANDBY_BEATS.length
+ || (mHeartbeat < job.getBaseHeartbeat() + mConstants.STANDBY_BEATS[bucket])) {
+ // TODO: log/trace that we're deferring the job due to bucketing if we hit this
+ if (job.getWhenStandbyDeferred() == 0) {
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, "Bucket deferral: " + mHeartbeat + " < "
+ + mNextBucketHeartbeat[job.getStandbyBucket()] + " for " + job);
+ }
+ job.setWhenStandbyDeferred(sElapsedRealtimeClock.millis());
}
- job.setWhenStandbyDeferred(sElapsedRealtimeClock.millis());
+ return false;
+ } else {
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, "Bucket deferred job aged into runnability at "
+ + mHeartbeat + " : " + job);
+ }
}
- return false;
}
// The expensive check last: validate that the defined package+service is
@@ -1984,6 +1997,11 @@
}
@Override
+ public void cancelJobsForUid(int uid, String reason) {
+ JobSchedulerService.this.cancelJobsForUid(uid, reason);
+ }
+
+ @Override
public void addBackingUpUid(int uid) {
synchronized (mLock) {
// No need to actually do anything here, since for a full backup the
@@ -2074,10 +2092,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/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 219bc61..36cacd7a 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -1149,8 +1149,10 @@
public void forEachJob(JobStatusFunctor functor) {
for (int uidIndex = mJobs.size() - 1; uidIndex >= 0; uidIndex--) {
ArraySet<JobStatus> jobs = mJobs.valueAt(uidIndex);
- for (int i = jobs.size() - 1; i >= 0; i--) {
- functor.process(jobs.valueAt(i));
+ if (jobs != null) {
+ for (int i = jobs.size() - 1; i >= 0; i--) {
+ functor.process(jobs.valueAt(i));
+ }
}
}
}
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..90c912a 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,18 +51,16 @@
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;
/**
* @hide
*/
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.
@@ -75,25 +75,10 @@
public static final int MSG_QUERY_MEMORY = 6;
public static final int MSG_HUB_RESET = 7;
- private static final String PRE_LOADED_GENERIC_UNKNOWN = "Preloaded app, unknown";
- private static final String PRE_LOADED_APP_NAME = PRE_LOADED_GENERIC_UNKNOWN;
- private static final String PRE_LOADED_APP_PUBLISHER = PRE_LOADED_GENERIC_UNKNOWN;
- private static final int PRE_LOADED_APP_MEM_REQ = 0;
-
private static final int OS_APP_INSTANCE = -1;
private final Context mContext;
- // TODO(b/69270990): Remove once old ContextHubManager API is deprecated
- // Service cache maintaining of instance ID to nanoapp infos
- private final ConcurrentHashMap<Integer, NanoAppInstanceInfo> mNanoAppHash =
- new ConcurrentHashMap<>();
- // The next available instance ID (managed by the service) to assign to a nanoapp
- private int mNextAvailableInstanceId = 0;
- // A map of the long nanoapp ID to instance ID managed by the service
- private final ConcurrentHashMap<Long, Integer> mNanoAppIdToInstanceMap =
- new ConcurrentHashMap<>();
-
private final ContextHubInfo[] mContextHubInfo;
private final RemoteCallbackList<IContextHubCallback> mCallbacksList =
new RemoteCallbackList<>();
@@ -104,6 +89,15 @@
// 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;
+
+ // The manager for the internal nanoapp state cache
+ private final NanoAppStateManager mNanoAppStateManager = new NanoAppStateManager();
+
/**
* Class extending the callback to register with a Context Hub.
*/
@@ -146,21 +140,35 @@
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, mNanoAppStateManager);
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 +176,7 @@
contextHubId, new ContextHubServiceCallback(contextHubId));
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while registering service callback for hub (ID = "
- + contextHubId + ")");
+ + contextHubId + ")", e);
}
}
@@ -185,6 +193,52 @@
}
/**
+ * 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 nanoAppHandle = mNanoAppStateManager.getNanoAppHandle(
+ contextHubId, message.getNanoAppId());
+
+ onMessageReceiptOldApi(
+ message.getMessageType(), contextHubId, nanoAppHandle,
+ 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 +246,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 +258,7 @@
public int registerCallback(IContextHubCallback callback) throws RemoteException {
checkPermissions();
mCallbacksList.register(callback);
+
Log.d(TAG, "Added callback, total callbacks " +
mCallbacksList.getRegisteredCallbackCount());
return 0;
@@ -260,15 +315,13 @@
* Creates an internal unload transaction callback to be used for old API clients
*
* @param contextHubId the ID of the hub to unload the nanoapp
- * @param nanoAppId the ID of the nanoapp to unload
* @return the callback interface
*/
- private IContextHubTransactionCallback createUnloadTransactionCallback(
- int contextHubId, long nanoAppId) {
+ private IContextHubTransactionCallback createUnloadTransactionCallback(int contextHubId) {
return new IContextHubTransactionCallback.Stub() {
@Override
public void onTransactionComplete(int result) {
- handleUnloadResponseOldApi(contextHubId, result, nanoAppId);
+ handleUnloadResponseOldApi(contextHubId, result);
}
@Override
@@ -292,29 +345,11 @@
@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);
}
};
}
- /**
- * Adds a new transaction to the transaction manager queue
- *
- * @param transaction the transaction to add
- * @return the result of adding the transaction
- */
- private int addTransaction(ContextHubServiceTransaction transaction) {
- int result = Result.OK;
- try {
- mTransactionManager.addTransaction(transaction);
- } catch (IllegalStateException e) {
- Log.e(TAG, e.getMessage());
- result = Result.TRANSACTION_PENDING; /* failed */
- }
-
- return result;
- }
-
@Override
public int loadNanoApp(int contextHubId, NanoApp app) throws RemoteException {
checkPermissions();
@@ -339,70 +374,50 @@
ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction(
contextHubId, nanoAppBinary, onCompleteCallback);
- int result = addTransaction(transaction);
- if (result != Result.OK) {
- Log.e(TAG, "Failed to load nanoapp with error code " + result);
- return -1;
- }
-
- // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
+ mTransactionManager.addTransaction(transaction);
return 0;
}
@Override
- public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
+ public int unloadNanoApp(int nanoAppHandle) throws RemoteException {
checkPermissions();
if (mContextHubProxy == null) {
return -1;
}
- NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
+ NanoAppInstanceInfo info =
+ mNanoAppStateManager.getNanoAppInstanceInfo(nanoAppHandle);
if (info == null) {
- Log.e(TAG, "Cannot find app with handle " + nanoAppInstanceHandle);
- return -1; //means failed
+ Log.e(TAG, "Cannot find nanoapp with handle " + nanoAppHandle);
+ return -1;
}
int contextHubId = info.getContexthubId();
long nanoAppId = info.getAppId();
IContextHubTransactionCallback onCompleteCallback =
- createUnloadTransactionCallback(contextHubId, nanoAppId);
+ createUnloadTransactionCallback(contextHubId);
ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction(
contextHubId, nanoAppId, onCompleteCallback);
- int result = addTransaction(transaction);
- if (result != Result.OK) {
- Log.e(TAG, "Failed to unload nanoapp with error code " + result);
- return -1;
- }
-
- // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
+ mTransactionManager.addTransaction(transaction);
return 0;
}
@Override
- public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle)
- throws RemoteException {
+ public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) throws RemoteException {
checkPermissions();
- // This assumes that all the nanoAppInfo is current. This is reasonable
- // for the use cases for tightly controlled nanoApps.
- if (mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
- return mNanoAppHash.get(nanoAppInstanceHandle);
- } else {
- Log.e(TAG, "Could not find nanoApp with handle " + nanoAppInstanceHandle);
- return null;
- }
+
+ return mNanoAppStateManager.getNanoAppInstanceInfo(nanoAppHandle);
}
@Override
public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
checkPermissions();
- ArrayList<Integer> foundInstances = new ArrayList<Integer>();
- for (Integer nanoAppInstance : mNanoAppHash.keySet()) {
- NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
-
+ ArrayList<Integer> foundInstances = new ArrayList<>();
+ for (NanoAppInstanceInfo info : mNanoAppStateManager.getNanoAppInstanceInfoCollection()) {
if (filter.testMatch(info)) {
- foundInstances.add(nanoAppInstance);
+ foundInstances.add(info.getHandle());
}
}
@@ -411,7 +426,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;
}
@@ -423,6 +442,8 @@
*
* @param contextHubId the ID of the hub to do the query
* @return the result of the query
+ *
+ * @throws IllegalStateException if the transaction queue is full
*/
private int queryNanoAppsInternal(int contextHubId) {
if (mContextHubProxy == null) {
@@ -434,7 +455,8 @@
ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction(
contextHubId, onCompleteCallback);
- return addTransaction(transaction);
+ mTransactionManager.addTransaction(transaction);
+ return Result.OK;
}
@Override
@@ -449,41 +471,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 "
+ Log.e(TAG, "Failed to send nanoapp message - nanoapp with handle "
+ nanoAppHandle + " does not exist.");
- result = Result.BAD_PARAMS;
}
}
- return (result == Result.OK ? 0 : -1);
+ return success ? 0 : -1;
}
/**
@@ -493,12 +511,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);
}
/**
@@ -513,28 +526,13 @@
return;
}
- // NOTE: The legacy JNI code used to do a query right after a load success
- // to synchronize the service cache. Instead store the binary that was requested to
- // load to update the cache later without doing a query.
- int instanceId = 0;
- long nanoAppId = nanoAppBinary.getNanoAppId();
- int nanoAppVersion = nanoAppBinary.getNanoAppVersion();
- if (result == TransactionResult.SUCCESS) {
- if (mNanoAppIdToInstanceMap.containsKey(nanoAppId)) {
- instanceId = mNanoAppIdToInstanceMap.get(nanoAppId);
- } else {
- instanceId = mNextAvailableInstanceId++;
- mNanoAppIdToInstanceMap.put(nanoAppId, instanceId);
- }
-
- addAppInstance(contextHubId, instanceId, nanoAppId, nanoAppVersion);
- }
-
byte[] data = new byte[5];
data[0] = (byte) result;
- ByteBuffer.wrap(data, 1, 4).order(ByteOrder.nativeOrder()).putInt(instanceId);
+ int nanoAppHandle = mNanoAppStateManager.getNanoAppHandle(
+ contextHubId, nanoAppBinary.getNanoAppId());
+ ByteBuffer.wrap(data, 1, 4).order(ByteOrder.nativeOrder()).putInt(nanoAppHandle);
- onMessageReceipt(MSG_LOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
+ onMessageReceiptOldApi(MSG_LOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
}
/**
@@ -542,17 +540,10 @@
*
* TODO(b/69270990): Remove this once the old APIs are obsolete.
*/
- private void handleUnloadResponseOldApi(
- int contextHubId, int result, long nanoAppId) {
- if (result == TransactionResult.SUCCESS) {
- int instanceId = mNanoAppIdToInstanceMap.get(nanoAppId);
- deleteAppInstance(instanceId);
- mNanoAppIdToInstanceMap.remove(nanoAppId);
- }
-
+ private void handleUnloadResponseOldApi(int contextHubId, int result) {
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 +568,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 + ")");
@@ -606,39 +596,126 @@
List<NanoAppState> nanoAppStateList =
ContextHubServiceUtil.createNanoAppStateList(nanoAppInfoList);
- updateServiceCache(contextHubId, nanoAppInfoList);
+ mNanoAppStateManager.updateCache(contextHubId, nanoAppInfoList);
mTransactionManager.onQueryResponse(nanoAppStateList);
}
/**
- * Updates the service's cache of the list of loaded nanoapps using a nanoapp list response.
- *
- * TODO(b/69270990): Remove this when the old API functionality is removed.
- *
- * @param contextHubId the ID of the hub the response came from
- * @param nanoAppInfoList the list of loaded nanoapps
+ * @param contextHubId the hub ID to validate
+ * @return {@code true} if the ID represents that of an available hub, {@code false} otherwise
*/
- private void updateServiceCache(int contextHubId, List<HubAppInfo> nanoAppInfoList) {
- synchronized (mNanoAppHash) {
- for (int instanceId : mNanoAppHash.keySet()) {
- if (mNanoAppHash.get(instanceId).getContexthubId() == contextHubId) {
- deleteAppInstance(instanceId);
- }
- }
-
- for (HubAppInfo appInfo : nanoAppInfoList) {
- int instanceId;
- long nanoAppId = appInfo.appId;
- if (mNanoAppIdToInstanceMap.containsKey(nanoAppId)) {
- instanceId = mNanoAppIdToInstanceMap.get(nanoAppId);
- } else {
- instanceId = mNextAvailableInstanceId++;
- mNanoAppIdToInstanceMap.put(nanoAppId, instanceId);
- }
-
- addAppInstance(contextHubId, instanceId, nanoAppId, appInfo.version);
+ 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);
+ }
+
+ /**
+ * Loads a nanoapp binary at the specified Context hub.
+ *
+ * @param contextHubId the ID of the hub to load the binary
+ * @param transactionCallback the client-facing transaction callback interface
+ * @param nanoAppBinary the binary to load
+ *
+ * @throws RemoteException
+ * @throws IllegalStateException if the transaction queue is full
+ */
+ @Override
+ public void loadNanoAppOnHub(
+ int contextHubId, IContextHubTransactionCallback transactionCallback,
+ NanoAppBinary nanoAppBinary) throws RemoteException {
+ checkPermissions();
+ if (!checkHalProxyAndContextHubId(
+ contextHubId, transactionCallback, ContextHubTransaction.TYPE_LOAD_NANOAPP)) {
+ return;
+ }
+ if (nanoAppBinary == null) {
+ Log.e(TAG, "NanoAppBinary cannot be null in loadNanoAppOnHub");
+ transactionCallback.onTransactionComplete(
+ ContextHubTransaction.TRANSACTION_FAILED_BAD_PARAMS);
+ return;
+ }
+
+ ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction(
+ contextHubId, nanoAppBinary, transactionCallback);
+ mTransactionManager.addTransaction(transaction);
+ }
+
+ /**
+ * Unloads a nanoapp from the specified Context Hub.
+ *
+ * @param contextHubId the ID of the hub to unload the nanoapp
+ * @param transactionCallback the client-facing transaction callback interface
+ * @param nanoAppId the ID of the nanoapp to unload
+ *
+ * @throws RemoteException
+ * @throws IllegalStateException if the transaction queue is full
+ */
+ @Override
+ public void unloadNanoAppFromHub(
+ int contextHubId, IContextHubTransactionCallback transactionCallback, long nanoAppId)
+ throws RemoteException {
+ checkPermissions();
+ if (!checkHalProxyAndContextHubId(
+ contextHubId, transactionCallback, ContextHubTransaction.TYPE_UNLOAD_NANOAPP)) {
+ return;
+ }
+
+ ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction(
+ contextHubId, nanoAppId, transactionCallback);
+ mTransactionManager.addTransaction(transaction);
+ }
+
+ /**
+ * Queries for a list of nanoapps from the specified Context hub.
+ *
+ * @param contextHubId the ID of the hub to query
+ * @param transactionCallback the client-facing transaction callback interface
+ *
+ * @throws RemoteException
+ * @throws IllegalStateException if the transaction queue is full
+ */
+ @Override
+ public void queryNanoApps(int contextHubId, IContextHubTransactionCallback transactionCallback)
+ throws RemoteException {
+ checkPermissions();
+ if (!checkHalProxyAndContextHubId(
+ contextHubId, transactionCallback, ContextHubTransaction.TYPE_QUERY_NANOAPPS)) {
+ return;
+ }
+
+ ContextHubServiceTransaction transaction =
+ mTransactionManager.createQueryTransaction(contextHubId, transactionCallback);
+ mTransactionManager.addTransaction(transaction);
}
@Override
@@ -656,18 +733,18 @@
pw.println("");
pw.println("=================== NANOAPPS ====================");
// Dump nanoAppHash
- for (Integer nanoAppInstance : mNanoAppHash.keySet()) {
- pw.println(nanoAppInstance + " : " + mNanoAppHash.get(nanoAppInstance).toString());
+ for (NanoAppInstanceInfo info : mNanoAppStateManager.getNanoAppInstanceInfoCollection()) {
+ pw.println(info);
}
// dump eventLog
}
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;
}
@@ -696,39 +773,39 @@
return 0;
}
- private int addAppInstance(int hubHandle, int appInstanceHandle, long appId, int appVersion) {
- // App Id encodes vendor & version
- NanoAppInstanceInfo appInfo = new NanoAppInstanceInfo();
-
- appInfo.setAppId(appId);
- appInfo.setAppVersion(appVersion);
- appInfo.setName(PRE_LOADED_APP_NAME);
- appInfo.setContexthubId(hubHandle);
- appInfo.setHandle(appInstanceHandle);
- appInfo.setPublisher(PRE_LOADED_APP_PUBLISHER);
- appInfo.setNeededExecMemBytes(PRE_LOADED_APP_MEM_REQ);
- appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
- appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
-
- String action;
- if (mNanoAppHash.containsKey(appInstanceHandle)) {
- action = "Updated";
- } else {
- action = "Added";
+ /**
+ * Validates the HAL proxy state and context hub ID to see if we can start the transaction.
+ *
+ * @param contextHubId the ID of the hub to start the transaction
+ * @param callback the client transaction callback interface
+ * @param transactionType the type of the transaction
+ *
+ * @return {@code true} if mContextHubProxy and contextHubId is valid, {@code false} otherwise
+ */
+ private boolean checkHalProxyAndContextHubId(
+ int contextHubId, IContextHubTransactionCallback callback,
+ @ContextHubTransaction.Type int transactionType) {
+ if (mContextHubProxy == null) {
+ try {
+ callback.onTransactionComplete(
+ ContextHubTransaction.TRANSACTION_FAILED_HAL_UNAVAILABLE);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException while calling onTransactionComplete", e);
+ }
+ return false;
+ }
+ if (!isValidContextHubId(contextHubId)) {
+ Log.e(TAG, "Cannot start "
+ + ContextHubTransaction.typeToString(transactionType, false /* upperCase */)
+ + " transaction for invalid hub ID " + contextHubId);
+ try {
+ callback.onTransactionComplete(ContextHubTransaction.TRANSACTION_FAILED_BAD_PARAMS);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException while calling onTransactionComplete", e);
+ }
+ return false;
}
- mNanoAppHash.put(appInstanceHandle, appInfo);
- Log.d(TAG, action + " app instance " + appInstanceHandle + " with id 0x"
- + Long.toHexString(appId) + " version 0x" + Integer.toHexString(appVersion));
-
- return 0;
- }
-
- private int deleteAppInstance(int appInstanceHandle) {
- if (mNanoAppHash.remove(appInstanceHandle) == null) {
- return -1;
- }
-
- return 0;
+ return true;
}
}
diff --git a/services/core/java/com/android/server/location/ContextHubServiceTransaction.java b/services/core/java/com/android/server/location/ContextHubServiceTransaction.java
index 66145bb..c1fc982 100644
--- a/services/core/java/com/android/server/location/ContextHubServiceTransaction.java
+++ b/services/core/java/com/android/server/location/ContextHubServiceTransaction.java
@@ -54,22 +54,14 @@
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
*/
- /* package */ void onTransactionComplete(int result) {
+ /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
}
/**
@@ -80,7 +72,8 @@
* @param result the result of the query
* @param nanoAppStateList the list of nanoapps given by the query response
*/
- /* package */ void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
+ /* package */ void onQueryResponse(
+ @ContextHubTransaction.Result int result, List<NanoAppState> nanoAppStateList) {
}
/**
@@ -134,28 +127,9 @@
return mIsComplete;
}
- /**
- * @return the human-readable string of this transaction's type
- */
- private String getTransactionTypeString() {
- switch (mTransactionType) {
- case ContextHubTransaction.TYPE_LOAD_NANOAPP:
- return "Load";
- case ContextHubTransaction.TYPE_UNLOAD_NANOAPP:
- return "Unload";
- case ContextHubTransaction.TYPE_ENABLE_NANOAPP:
- return "Enable";
- case ContextHubTransaction.TYPE_DISABLE_NANOAPP:
- return "Disable";
- case ContextHubTransaction.TYPE_QUERY_NANOAPPS:
- return "Query";
- default:
- return "Unknown";
- }
- }
-
@Override
public String toString() {
- return getTransactionTypeString() + " transaction (ID = " + mTransactionId + ")";
+ return ContextHubTransaction.typeToString(mTransactionType, true /* upperCase */)
+ + " transaction (ID = " + mTransactionId + ")";
}
}
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..00252bc 100644
--- a/services/core/java/com/android/server/location/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/ContextHubTransactionManager.java
@@ -50,7 +50,7 @@
/*
* Maximum number of transaction requests that can be pending at a time
*/
- private static final int MAX_PENDING_REQUESTS = 10;
+ private static final int MAX_PENDING_REQUESTS = 10000;
/*
* The proxy to talk to the Context Hub
@@ -58,6 +58,16 @@
private final IContexthub mContextHubProxy;
/*
+ * The manager for all clients for the service.
+ */
+ private final ContextHubClientManager mClientManager;
+
+ /*
+ * The nanoapp state manager for the service
+ */
+ private final NanoAppStateManager mNanoAppStateManager;
+
+ /*
* A queue containing the current transactions
*/
private final ArrayDeque<ContextHubServiceTransaction> mTransactionQueue = new ArrayDeque<>();
@@ -73,8 +83,12 @@
private final ScheduledThreadPoolExecutor mTimeoutExecutor = new ScheduledThreadPoolExecutor(1);
private ScheduledFuture<?> mTimeoutFuture = null;
- /* package */ ContextHubTransactionManager(IContexthub contextHubProxy) {
+ /* package */ ContextHubTransactionManager(
+ IContexthub contextHubProxy, ContextHubClientManager clientManager,
+ NanoAppStateManager nanoAppStateManager) {
mContextHubProxy = contextHubProxy;
+ mClientManager = clientManager;
+ mNanoAppStateManager = nanoAppStateManager;
}
/**
@@ -99,22 +113,28 @@
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) {
+ /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
+ if (result == ContextHubTransaction.TRANSACTION_SUCCESS) {
+ // NOTE: The legacy JNI code used to do a query right after a load success
+ // to synchronize the service cache. Instead store the binary that was
+ // requested to load to update the cache later without doing a query.
+ mNanoAppStateManager.addNanoAppInstance(
+ contextHubId, nanoAppBinary.getNanoAppId(),
+ nanoAppBinary.getNanoAppVersion());
+ }
try {
onCompleteCallback.onTransactionComplete(result);
+ if (result == ContextHubTransaction.TRANSACTION_SUCCESS) {
+ 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 +159,23 @@
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) {
+ /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
+ if (result == ContextHubTransaction.TRANSACTION_SUCCESS) {
+ mNanoAppStateManager.removeNanoAppInstance(contextHubId, nanoAppId);
+ }
try {
onCompleteCallback.onTransactionComplete(result);
+ if (result == ContextHubTransaction.TRANSACTION_SUCCESS) {
+ 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,23 +197,23 @@
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(@ContextHubTransaction.Result int result) {
+ onQueryResponse(result, Collections.emptyList());
}
@Override
- /* package */ void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
+ /* package */ void onQueryResponse(
+ @ContextHubTransaction.Result int result, List<NanoAppState> nanoAppStateList) {
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);
}
}
};
@@ -202,7 +223,8 @@
* Adds a new transaction to the queue.
*
* If there was no pending transaction at the time, the transaction that was added will be
- * started in this method.
+ * started in this method. If there were too many transactions in the queue, an exception will
+ * be thrown.
*
* @param transaction the transaction to add
* @throws IllegalStateException if the queue is full
@@ -211,7 +233,7 @@
synchronized void addTransaction(
ContextHubServiceTransaction transaction) throws IllegalStateException {
if (mTransactionQueue.size() == MAX_PENDING_REQUESTS) {
- throw new IllegalStateException("Transaction transaction queue is full (capacity = "
+ throw new IllegalStateException("Transaction queue is full (capacity = "
+ MAX_PENDING_REQUESTS + ")");
}
mTransactionQueue.add(transaction);
@@ -225,7 +247,7 @@
* Handles a transaction response from a Context Hub.
*
* @param transactionId the transaction ID of the response
- * @param result the result of the transaction
+ * @param result the result of the transaction as defined by the HAL TransactionResult
*/
/* package */
synchronized void onTransactionResponse(int transactionId, int result) {
@@ -240,7 +262,10 @@
return;
}
- transaction.onTransactionComplete(result);
+ transaction.onTransactionComplete(
+ (result == TransactionResult.SUCCESS) ?
+ ContextHubTransaction.TRANSACTION_SUCCESS :
+ ContextHubTransaction.TRANSACTION_FAILED_AT_HUB);
removeTransactionAndStartNext();
}
@@ -261,7 +286,7 @@
return;
}
- transaction.onQueryResponse(TransactionResult.SUCCESS, nanoAppStateList);
+ transaction.onQueryResponse(ContextHubTransaction.TRANSACTION_SUCCESS, nanoAppStateList);
removeTransactionAndStartNext();
}
@@ -320,7 +345,8 @@
synchronized (this) {
if (!transaction.isComplete()) {
Log.d(TAG, transaction + " timed out");
- transaction.onTimeout();
+ transaction.onTransactionComplete(
+ ContextHubTransaction.TRANSACTION_FAILED_TIMEOUT);
removeTransactionAndStartNext();
}
@@ -331,6 +357,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/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 0b511f2..b324002 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -233,13 +233,13 @@
private static final int AGPS_SETID_TYPE_IMSI = 1;
private static final int AGPS_SETID_TYPE_MSISDN = 2;
- private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
- private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
+ private static final int GPS_GEOFENCE_UNAVAILABLE = 1 << 0L;
+ private static final int GPS_GEOFENCE_AVAILABLE = 1 << 1L;
// GPS Geofence errors. Should match GeofenceStatus enum in IGnssGeofenceCallback.hal.
private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
- private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101;
+ private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101;
private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
@@ -253,6 +253,7 @@
private static class GpsRequest {
public ProviderRequest request;
public WorkSource source;
+
public GpsRequest(ProviderRequest request, WorkSource source) {
this.request = request;
this.source = source;
@@ -280,15 +281,15 @@
// how often to request NTP time, in milliseconds
// current setting 24 hours
- private static final long NTP_INTERVAL = 24*60*60*1000;
+ private static final long NTP_INTERVAL = 24 * 60 * 60 * 1000;
// how long to wait if we have a network error in NTP or XTRA downloading
// the initial value of the exponential backoff
// current setting - 5 minutes
- private static final long RETRY_INTERVAL = 5*60*1000;
+ private static final long RETRY_INTERVAL = 5 * 60 * 1000;
// how long to wait if we have a network error in NTP or XTRA downloading
// the max value of the exponential backoff
// current setting - 4 hours
- private static final long MAX_RETRY_INTERVAL = 4*60*60*1000;
+ private static final long MAX_RETRY_INTERVAL = 4 * 60 * 60 * 1000;
// Timeout when holding wakelocks for downloading XTRA data.
private static final long DOWNLOAD_XTRA_DATA_TIMEOUT_MS = 60 * 1000;
@@ -321,6 +322,9 @@
// requested frequency of fixes, in milliseconds
private int mFixInterval = 1000;
+ // true if low power mode for the GNSS chipset is part of the latest request.
+ private boolean mLowPowerMode = false;
+
// true if we started navigation
private boolean mStarted;
@@ -398,7 +402,6 @@
private final static String LPP_PROFILE = "persist.sys.gps.lpp";
-
private final PowerManager mPowerManager;
private final AlarmManager mAlarmManager;
private final PendingIntent mWakeupIntent;
@@ -459,26 +462,27 @@
*/
private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback =
new ConnectivityManager.NetworkCallback() {
- @Override
- public void onAvailable(Network network) {
- if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
- requestUtcTime();
- }
- if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
- if (mSupportsXtra) {
- // Download only if supported, (prevents an unneccesary on-boot download)
- xtraDownloadRequest();
+ @Override
+ public void onAvailable(Network network) {
+ if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
+ requestUtcTime();
+ }
+ if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
+ if (mSupportsXtra) {
+ // Download only if supported, (prevents an unneccesary on-boot
+ // download)
+ xtraDownloadRequest();
+ }
+ }
+ // Always on, notify HAL so it can get data it needs
+ sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
}
- }
- // Always on, notify HAL so it can get data it needs
- sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
- }
- @Override
- public void onLost(Network network) {
- sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
- }
- };
+ @Override
+ public void onLost(Network network) {
+ sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
+ }
+ };
/**
* Callback used to listen for availability of a requested SUPL connection.
@@ -487,20 +491,21 @@
*/
private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback =
new ConnectivityManager.NetworkCallback() {
- @Override
- public void onAvailable(Network network) {
- // Specific to a change to a SUPL enabled network becoming ready
- sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
- }
+ @Override
+ public void onAvailable(Network network) {
+ // Specific to a change to a SUPL enabled network becoming ready
+ sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
+ }
- @Override
- public void onLost(Network network) {
- releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
- }
- };
+ @Override
+ public void onLost(Network network) {
+ releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
+ }
+ };
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Override public void onReceive(Context context, Intent intent) {
+ @Override
+ public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
if (action == null) {
@@ -524,11 +529,11 @@
private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
new OnSubscriptionsChangedListener() {
- @Override
- public void onSubscriptionsChanged() {
- sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null);
- }
- };
+ @Override
+ public void onSubscriptionsChanged() {
+ sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null);
+ }
+ };
private void subscriptionOrSimChanged(Context context) {
if (DEBUG) Log.d(TAG, "received SIM related action: ");
@@ -599,8 +604,8 @@
String lpp_prof = SystemProperties.get(LPP_PROFILE);
if (!TextUtils.isEmpty(lpp_prof)) {
- // override default value of this if lpp_prof is not empty
- properties.setProperty("LPP_PROFILE", lpp_prof);
+ // override default value of this if lpp_prof is not empty
+ properties.setProperty("LPP_PROFILE", lpp_prof);
}
/*
* Overlay carrier properties from a debug configuration file.
@@ -608,7 +613,7 @@
loadPropertiesFromFile(DEBUG_PROPERTIES_FILE, properties);
// TODO: we should get rid of C2K specific setting.
setSuplHostPort(properties.getProperty("SUPL_HOST"),
- properties.getProperty("SUPL_PORT"));
+ properties.getProperty("SUPL_PORT"));
mC2KServerHost = properties.getProperty("C2K_HOST");
String portString = properties.getProperty("C2K_PORT");
if (mC2KServerHost != null && portString != null) {
@@ -625,24 +630,26 @@
put("SUPL_MODE", (val) -> native_set_supl_mode(val));
put("SUPL_ES", (val) -> native_set_supl_es(val));
put("LPP_PROFILE", (val) -> native_set_lpp_profile(val));
- put("A_GLONASS_POS_PROTOCOL_SELECT", (val) -> native_set_gnss_pos_protocol_select(val));
- put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL", (val) -> native_set_emergency_supl_pdn(val));
+ put("A_GLONASS_POS_PROTOCOL_SELECT",
+ (val) -> native_set_gnss_pos_protocol_select(val));
+ put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL",
+ (val) -> native_set_emergency_supl_pdn(val));
put("GPS_LOCK", (val) -> native_set_gps_lock(val));
}
};
- for(Entry<String, SetCarrierProperty> entry : map.entrySet()) {
+ for (Entry<String, SetCarrierProperty> entry : map.entrySet()) {
String propertyName = entry.getKey();
String propertyValueString = properties.getProperty(propertyName);
if (propertyValueString != null) {
try {
- int propertyValueInt = Integer.decode(propertyValueString);
- boolean result = entry.getValue().set(propertyValueInt);
- if (result == false) {
- Log.e(TAG, "Unable to set " + propertyName);
- }
+ int propertyValueInt = Integer.decode(propertyValueString);
+ boolean result = entry.getValue().set(propertyValueInt);
+ if (result == false) {
+ Log.e(TAG, "Unable to set " + propertyName);
+ }
} catch (NumberFormatException e) {
- Log.e(TAG, "unable to parse propertyName: " + propertyValueString);
+ Log.e(TAG, "unable to parse propertyName: " + propertyValueString);
}
}
}
@@ -663,7 +670,7 @@
}
private void loadPropertiesFromResource(Context context,
- Properties properties) {
+ Properties properties) {
String[] configValues = context.getResources().getStringArray(
com.android.internal.R.array.config_gpsParameters);
for (String item : configValues) {
@@ -681,7 +688,7 @@
}
private boolean loadPropertiesFromFile(String filename,
- Properties properties) {
+ Properties properties) {
try {
File file = new File(filename);
FileInputStream stream = null;
@@ -717,11 +724,11 @@
PowerManager.PARTIAL_WAKE_LOCK, DOWNLOAD_EXTRA_WAKELOCK_KEY);
mDownloadXtraWakeLock.setReferenceCounted(true);
- mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+ mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
- mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ mConnMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
// App ops service to keep track of who is accessing the GPS
mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
@@ -744,8 +751,8 @@
// Create a GPS net-initiated handler.
mNIHandler = new GpsNetInitiatedHandler(context,
- mNetInitiatedListener,
- mSuplEsEnabled);
+ mNetInitiatedListener,
+ mSuplEsEnabled);
mListenerHelper = new GnssStatusListenerHelper(mHandler) {
@Override
@@ -766,8 +773,23 @@
}
@Override
- protected boolean registerWithService() {
- return native_start_measurement_collection();
+ protected int registerWithService() {
+ int devOptions = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Global.DEVELOPMENT_SETTINGS_ENABLED , 0);
+ int fullTrackingToggled = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING , 0);
+ boolean result = false;
+ if (devOptions == 1 /* Developer Mode enabled */
+ && fullTrackingToggled == 1 /* Raw Measurements Full Tracking enabled */) {
+ result = native_start_measurement_collection(true /* enableFullTracking */);
+ } else {
+ result = native_start_measurement_collection(false /* enableFullTracking */);
+ }
+ if (result) {
+ return RemoteListenerHelper.RESULT_SUCCESS;
+ } else {
+ return RemoteListenerHelper.RESULT_INTERNAL_ERROR;
+ }
}
@Override
@@ -788,8 +810,13 @@
}
@Override
- protected boolean registerWithService() {
- return native_start_navigation_message_collection();
+ protected int registerWithService() {
+ boolean result = native_start_navigation_message_collection();
+ if (result) {
+ return RemoteListenerHelper.RESULT_SUCCESS;
+ } else {
+ return RemoteListenerHelper.RESULT_INTERNAL_ERROR;
+ }
}
@Override
@@ -1116,9 +1143,9 @@
* Checks what SUPL mode to use, according to the AGPS mode as well as the
* allowed mode from properties.
*
- * @param properties GPS properties
+ * @param properties GPS properties
* @param agpsEnabled whether AGPS is enabled by settings value
- * @param singleShot whether "singleshot" is needed
+ * @param singleShot whether "singleshot" is needed
* @return SUPL mode (MSA vs MSB vs STANDALONE)
*/
private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
@@ -1222,7 +1249,7 @@
}
private void updateStatus(int status, int svCount, int meanCn0, int maxCn0) {
- if (status != mStatus || svCount != mSvCount || meanCn0 != mMeanCn0 || maxCn0 != mMaxCn0 ) {
+ if (status != mStatus || svCount != mSvCount || meanCn0 != mMeanCn0 || maxCn0 != mMaxCn0) {
mStatus = status;
mSvCount = svCount;
mMeanCn0 = meanCn0;
@@ -1284,7 +1311,7 @@
updateClientUids(mWorkSource);
mFixInterval = (int) mProviderRequest.interval;
-
+ mLowPowerMode = (boolean) mProviderRequest.lowPowerMode;
// check for overflow
if (mFixInterval != mProviderRequest.interval) {
Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
@@ -1293,10 +1320,10 @@
// apply request to GPS engine
if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
- // change period
+ // change period and/or lowPowerMode
if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
- mFixInterval, 0, 0)) {
- Log.e(TAG, "set_position_mode failed in setMinTime()");
+ mFixInterval, 0, 0, mLowPowerMode)) {
+ Log.e(TAG, "set_position_mode failed in updateRequirements");
}
} else if (!mStarted) {
// start GPS
@@ -1323,7 +1350,7 @@
// Update sources that were not previously tracked.
if (newWork != null) {
int lastuid = -1;
- for (int i=0; i<newWork.size(); i++) {
+ for (int i = 0; i < newWork.size(); i++) {
try {
int uid = newWork.get(i);
mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
@@ -1341,7 +1368,7 @@
// Update sources that are no longer tracked.
if (goneWork != null) {
int lastuid = -1;
- for (int i=0; i<goneWork.size(); i++) {
+ for (int i = 0; i < goneWork.size(); i++) {
try {
int uid = goneWork.get(i);
mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
@@ -1455,13 +1482,13 @@
boolean agpsEnabled =
(Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
+ Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
if (DEBUG) {
String mode;
- switch(mPositionMode) {
+ switch (mPositionMode) {
case GPS_POSITION_MODE_STANDALONE:
mode = "standalone";
break;
@@ -1479,8 +1506,9 @@
}
int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
+ mLowPowerMode = (boolean) mProviderRequest.lowPowerMode;
if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
- interval, 0, 0)) {
+ interval, 0, 0, mLowPowerMode)) {
mStarted = false;
Log.e(TAG, "set_position_mode failed in startNavigating()");
return;
@@ -1578,7 +1606,7 @@
mLastFixTime = SystemClock.elapsedRealtime();
// report time to first fix
if (mTimeToFirstFix == 0 && hasLatLong) {
- mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
+ mTimeToFirstFix = (int) (mLastFixTime - mFixRequestTime);
if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix);
@@ -1604,12 +1632,12 @@
updateStatus(LocationProvider.AVAILABLE, mSvCount, mMeanCn0, mMaxCn0);
}
- if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
- mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
+ if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
+ mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
if (DEBUG) Log.d(TAG, "got fix, hibernating");
hibernate();
}
- }
+ }
/**
* called from native code to update our status
@@ -1650,10 +1678,10 @@
*/
private void reportSvStatus() {
int svCount = native_read_sv_status(mSvidWithFlags,
- mCn0s,
- mSvElevations,
- mSvAzimuths,
- mSvCarrierFreqs);
+ mCn0s,
+ mSvElevations,
+ mSvAzimuths,
+ mSvCarrierFreqs);
mListenerHelper.onSvStatusChanged(
svCount,
mSvidWithFlags,
@@ -1676,7 +1704,7 @@
if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
++usedInFixCount;
if (mCn0s[i] > maxCn0) {
- maxCn0 = (int)mCn0s[i];
+ maxCn0 = (int) mCn0s[i];
}
meanCn0 += mCn0s[i];
}
@@ -1693,7 +1721,7 @@
((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
? "" : "U") +
((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY) == 0
- ? "" : "F"));
+ ? "" : "F"));
}
}
if (usedInFixCount > 0) {
@@ -1703,7 +1731,7 @@
updateStatus(mStatus, usedInFixCount, meanCn0, maxCn0);
if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
- SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
+ SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
// send an intent to notify that the GPS is no longer receiving fixes.
Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
@@ -1843,14 +1871,17 @@
* Returns the GNSS batching size
*/
int getSize();
+
/**
* Starts the hardware batching operation
*/
boolean start(long periodNanos, boolean wakeOnFifoFull);
+
/**
* Forces a flush of existing locations from the hardware batching
*/
void flush();
+
/**
* Stops the batching operation
*/
@@ -1866,6 +1897,7 @@
public int getSize() {
return native_get_batch_size();
}
+
@Override
public boolean start(long periodNanos, boolean wakeOnFifoFull) {
if (periodNanos <= 0) {
@@ -1875,10 +1907,12 @@
}
return native_start_batch(periodNanos, wakeOnFifoFull);
}
+
@Override
public void flush() {
native_flush_batch();
}
+
@Override
public boolean stop() {
return native_stop_batch();
@@ -1911,7 +1945,7 @@
private void enableBatching() {
if (!native_init_batching()) {
Log.e(TAG, "Failed to initialize GNSS batching");
- };
+ }
}
/**
@@ -1927,7 +1961,9 @@
*/
private void reportLocationBatch(Location[] locationArray) {
List<Location> locations = new ArrayList<>(Arrays.asList(locationArray));
- if(DEBUG) { Log.d(TAG, "Location batch of size " + locationArray.length + "reported"); }
+ if (DEBUG) {
+ Log.d(TAG, "Location batch of size " + locationArray.length + " reported");
+ }
try {
mILocationManager.reportLocationBatch(locations);
} catch (RemoteException e) {
@@ -1947,7 +1983,7 @@
* Converts the GPS HAL status to the internal Geofence Hardware status.
*/
private int getGeofenceStatus(int status) {
- switch(status) {
+ switch (status) {
case GPS_GEOFENCE_OPERATION_SUCCESS:
return GeofenceHardware.GEOFENCE_SUCCESS;
case GPS_GEOFENCE_ERROR_GENERIC:
@@ -1970,7 +2006,7 @@
* All geofence callbacks are called on the same thread
*/
private void reportGeofenceTransition(int geofenceId, Location location, int transition,
- long transitionTimestamp) {
+ long transitionTimestamp) {
if (mGeofenceHardwareImpl == null) {
mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
}
@@ -1992,7 +2028,7 @@
mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
}
int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
- if(status == GPS_GEOFENCE_AVAILABLE) {
+ if (status == GPS_GEOFENCE_AVAILABLE) {
monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
}
mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
@@ -2048,12 +2084,13 @@
private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
// Sends a response for an NI request to HAL.
@Override
- public boolean sendNiResponse(int notificationId, int userResponse)
- {
+ public boolean sendNiResponse(int notificationId, int userResponse) {
// TODO Add Permission check
- if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
- ", response: " + userResponse);
+ if (DEBUG) {
+ Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
+ ", response: " + userResponse);
+ }
native_send_ni_response(notificationId, userResponse);
return true;
}
@@ -2074,8 +2111,7 @@
String text,
int requestorIdEncoding,
int textEncoding
- )
- {
+ ) {
Log.i(TAG, "reportNiNotification: entered");
Log.i(TAG, "notificationId: " + notificationId +
", niType: " + niType +
@@ -2094,7 +2130,8 @@
notification.niType = niType;
notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
- notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
+ notification.privacyOverride =
+ (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
notification.timeout = timeout;
notification.defaultResponse = defaultResponse;
notification.requestorId = requestorId;
@@ -2126,8 +2163,7 @@
data = data_temp;
type = AGPS_SETID_TYPE_IMSI;
}
- }
- else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
+ } else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
String data_temp = phone.getLine1Number();
if (data_temp == null) {
// This means the framework does not have the SIM card ready.
@@ -2161,14 +2197,14 @@
if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
&& (phone.getNetworkOperator().length() > 3)) {
int type;
- int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
+ int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0, 3));
int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
int networkType = phone.getNetworkType();
if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
- || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
- || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
- || networkType == TelephonyManager.NETWORK_TYPE_HSPA
- || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
+ || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
+ || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
+ || networkType == TelephonyManager.NETWORK_TYPE_HSPA
+ || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
} else {
type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
@@ -2176,7 +2212,7 @@
native_agps_set_ref_location_cellid(type, mcc, mnc,
gsm_cell.getLac(), gsm_cell.getCid());
} else {
- Log.e(TAG,"Error getting cell location info.");
+ Log.e(TAG, "Error getting cell location info.");
}
} else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
Log.e(TAG, "CDMA not supported.");
@@ -2269,7 +2305,7 @@
* restart.
*/
boolean isInitialized = native_init();
- if(!isInitialized) {
+ if (!isInitialized) {
Log.w(TAG, "Native initialization failed at bootup");
} else {
native_cleanup();
@@ -2280,7 +2316,8 @@
reloadGpsProperties(mContext, mProperties);
// TODO: When this object "finishes" we should unregister by invoking
- // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
+ // SubscriptionManager.getInstance(mContext).unregister
+ // (mOnSubscriptionsChangedListener);
// This is not strictly necessary because it will be unregistered if the
// notification fails but it is good form.
@@ -2359,12 +2396,18 @@
handleUpdateLocation(location);
}
}
+
@Override
- public void onStatusChanged(String provider, int status, Bundle extras) { }
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ }
+
@Override
- public void onProviderEnabled(String provider) { }
+ public void onProviderEnabled(String provider) {
+ }
+
@Override
- public void onProviderDisabled(String provider) { }
+ public void onProviderDisabled(String provider) {
+ }
}
private String getSelectedApn() {
@@ -2373,7 +2416,7 @@
try {
cursor = mContext.getContentResolver().query(
uri,
- new String[] { "apn" },
+ new String[]{"apn"},
null /* selection */,
null /* selectionArgs */,
Carriers.DEFAULT_SORT_ORDER);
@@ -2404,7 +2447,7 @@
try {
cursor = mContext.getContentResolver().query(
Carriers.CONTENT_URI,
- new String[] { Carriers.PROTOCOL },
+ new String[]{Carriers.PROTOCOL},
selection,
null,
Carriers.DEFAULT_SORT_ORDER);
@@ -2461,7 +2504,7 @@
/**
* @return {@code true} if there is a data network available for outgoing connections,
- * {@code false} otherwise.
+ * {@code false} otherwise.
*/
private boolean isDataNetworkConnected() {
NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
@@ -2482,7 +2525,7 @@
* @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
*/
private String agpsDataConnStateAsString() {
- switch(mAGpsDataConnectionState) {
+ switch (mAGpsDataConnectionState) {
case AGPS_DATA_CONNECTION_CLOSED:
return "CLOSED";
case AGPS_DATA_CONNECTION_OPEN:
@@ -2549,12 +2592,12 @@
}
-
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
StringBuilder s = new StringBuilder();
s.append(" mStarted=").append(mStarted).append('\n');
s.append(" mFixInterval=").append(mFixInterval).append('\n');
+ s.append(" mLowPowerMode=").append(mLowPowerMode).append('\n');
s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
s.append(" ( ");
@@ -2618,29 +2661,45 @@
// preallocated to avoid memory allocation in reportNmea()
private byte[] mNmeaBuffer = new byte[120];
- static { class_init_native(); }
+ static {
+ class_init_native();
+ }
+
private static native void class_init_native();
+
private static native boolean native_is_supported();
+
private static native boolean native_is_agps_ril_supported();
+
private static native boolean native_is_gnss_configuration_supported();
private native boolean native_init();
+
private native void native_cleanup();
+
private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
- int preferred_accuracy, int preferred_time);
+ int preferred_accuracy, int preferred_time, boolean lowPowerMode);
+
private native boolean native_start();
+
private native boolean native_stop();
+
private native void native_delete_aiding_data(int flags);
+
// returns number of SVs
// mask[0] is ephemeris mask and mask[1] is almanac mask
private native int native_read_sv_status(int[] prnWithFlags, float[] cn0s, float[] elevations,
float[] azimuths, float[] carrierFrequencies);
+
private native int native_read_nmea(byte[] buffer, int bufferSize);
+
private native void native_inject_location(double latitude, double longitude, float accuracy);
// XTRA Support
private native void native_inject_time(long time, long timeReference, int uncertainty);
+
private native boolean native_supports_xtra();
+
private native void native_inject_xtra_data(byte[] data, int length);
// DEBUG Support
@@ -2648,9 +2707,13 @@
// AGPS Support
private native void native_agps_data_conn_open(String apn, int apnIpType);
+
private native void native_agps_data_conn_closed();
+
private native void native_agps_data_conn_failed();
- private native void native_agps_ni_message(byte [] msg, int length);
+
+ private native void native_agps_ni_message(byte[] msg, int length);
+
private native void native_set_agps_server(int type, String hostname, int port);
// Network-initiated (NI) Support
@@ -2659,6 +2722,7 @@
// AGPS ril suport
private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
int lac, int cid);
+
private native void native_agps_set_id(int type, String setid);
private native void native_update_network_state(boolean connected, int type,
@@ -2666,38 +2730,57 @@
// Hardware Geofence support.
private static native boolean native_is_geofence_supported();
+
private static native boolean native_add_geofence(int geofenceId, double latitude,
- double longitude, double radius, int lastTransition,int monitorTransitions,
+ double longitude, double radius, int lastTransition, int monitorTransitions,
int notificationResponsivenes, int unknownTimer);
+
private static native boolean native_remove_geofence(int geofenceId);
+
private static native boolean native_resume_geofence(int geofenceId, int transitions);
+
private static native boolean native_pause_geofence(int geofenceId);
// Gps Hal measurements support.
private static native boolean native_is_measurement_supported();
- private native boolean native_start_measurement_collection();
+
+ private native boolean native_start_measurement_collection(boolean enableFullTracking);
+
private native boolean native_stop_measurement_collection();
// Gps Navigation message support.
private static native boolean native_is_navigation_message_supported();
+
private native boolean native_start_navigation_message_collection();
+
private native boolean native_stop_navigation_message_collection();
// GNSS Configuration
private static native boolean native_set_supl_version(int version);
+
private static native boolean native_set_supl_mode(int mode);
+
private static native boolean native_set_supl_es(int es);
+
private static native boolean native_set_lpp_profile(int lppProfile);
+
private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect);
+
private static native boolean native_set_gps_lock(int gpsLock);
+
private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
// GNSS Batching
private static native int native_get_batch_size();
+
private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull);
+
private static native void native_flush_batch();
+
private static native boolean native_stop_batch();
+
private static native boolean native_init_batching();
+
private static native void native_cleanup_batching();
}
diff --git a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
index 924520b..477dae6 100644
--- a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
@@ -40,11 +40,11 @@
public void onMeasurementsAvailable(final GnssMeasurementsEvent event) {
ListenerOperation<IGnssMeasurementsListener> operation =
new ListenerOperation<IGnssMeasurementsListener>() {
- @Override
- public void execute(IGnssMeasurementsListener listener) throws RemoteException {
- listener.onGnssMeasurementsReceived(event);
- }
- };
+ @Override
+ public void execute(IGnssMeasurementsListener listener) throws RemoteException {
+ listener.onGnssMeasurementsReceived(event);
+ }
+ };
foreach(operation);
}
@@ -70,6 +70,9 @@
case RESULT_INTERNAL_ERROR:
status = GnssMeasurementsEvent.Callback.STATUS_NOT_SUPPORTED;
break;
+ case RESULT_NOT_ALLOWED:
+ status = GnssMeasurementsEvent.Callback.STATUS_NOT_ALLOWED;
+ break;
case RESULT_GPS_LOCATION_DISABLED:
status = GnssMeasurementsEvent.Callback.STATUS_LOCATION_DISABLED;
break;
diff --git a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
index fe2bb38..124220f 100644
--- a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
@@ -30,8 +30,8 @@
}
@Override
- protected boolean registerWithService() {
- return true;
+ protected int registerWithService() {
+ return RemoteListenerHelper.RESULT_SUCCESS;
}
@Override
diff --git a/services/core/java/com/android/server/location/NanoAppStateManager.java b/services/core/java/com/android/server/location/NanoAppStateManager.java
new file mode 100644
index 0000000..81c4784
--- /dev/null
+++ b/services/core/java/com/android/server/location/NanoAppStateManager.java
@@ -0,0 +1,190 @@
+/*
+ * 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.annotation.Nullable;
+import android.hardware.contexthub.V1_0.HubAppInfo;
+import android.hardware.location.NanoAppInstanceInfo;
+import android.util.Log;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Manages the state of loaded nanoapps at the Context Hubs.
+ *
+ * This class maintains a list of nanoapps that have been informed as loaded at the hubs. The state
+ * should be updated based on the hub callbacks (defined in IContexthubCallback.hal), as a result
+ * of either loadNanoApp, unloadNanoApp, or queryApps.
+ *
+ * The state tracked by this manager is used by clients of ContextHubService that use the old APIs.
+ *
+ * TODO(b/69270990): Remove this class and its logic once the old API is deprecated.
+ *
+ * @hide
+ */
+/* package */ class NanoAppStateManager {
+ private static final String TAG = "NanoAppStateManager";
+
+ /*
+ * Enables verbose debug logs for this class.
+ */
+ private static final boolean ENABLE_LOG_DEBUG = true;
+
+ /*
+ * Service cache maintaining of handle to nanoapp infos.
+ */
+ private final HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash = new HashMap<>();
+
+ /*
+ * The next nanoapp handle to use.
+ */
+ private int mNextHandle = 0;
+
+ /**
+ * @param nanoAppHandle the nanoapp handle
+ * @return the NanoAppInstanceInfo for the given nanoapp, or null if the nanoapp does not exist
+ * in the cache
+ */
+ @Nullable
+ /* package */
+ synchronized NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) {
+ return mNanoAppHash.get(nanoAppHandle);
+ }
+
+ /**
+ * @return a collection of NanoAppInstanceInfo objects in the cache
+ */
+ /* package */
+ synchronized Collection<NanoAppInstanceInfo> getNanoAppInstanceInfoCollection() {
+ return mNanoAppHash.values();
+ }
+
+ /**
+ * @param contextHubId the ID of the hub to search for the instance
+ * @param nanoAppId the unique 64-bit ID of the nanoapp
+ * @return the nanoapp handle, -1 if the nanoapp is not in the cache
+ */
+ /* package */
+ synchronized int getNanoAppHandle(int contextHubId, long nanoAppId) {
+ for (NanoAppInstanceInfo info : mNanoAppHash.values()) {
+ if (info.getContexthubId() == contextHubId && info.getAppId() == nanoAppId) {
+ return info.getHandle();
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Adds a nanoapp instance to the cache.
+ *
+ * If the cache already contained the nanoapp, the entry is removed and a new nanoapp handle is
+ * generated.
+ *
+ * @param contextHubId the ID of the hub the nanoapp is loaded in
+ * @param nanoAppId the unique 64-bit ID of the nanoapp
+ * @param nanoAppVersion the version of the nanoapp
+ */
+ /* package */
+ synchronized void addNanoAppInstance(int contextHubId, long nanoAppId, int nanoAppVersion) {
+ removeNanoAppInstance(contextHubId, nanoAppId);
+ if (mNanoAppHash.size() == Integer.MAX_VALUE) {
+ Log.e(TAG, "Error adding nanoapp instance: max limit exceeded");
+ return;
+ }
+
+ int nanoAppHandle = mNextHandle;
+ for (int i = 0; i <= Integer.MAX_VALUE; i++) {
+ if (!mNanoAppHash.containsKey(nanoAppHandle)) {
+ mNanoAppHash.put(nanoAppHandle, new NanoAppInstanceInfo(
+ nanoAppHandle, nanoAppId, nanoAppVersion, contextHubId));
+ mNextHandle = (nanoAppHandle == Integer.MAX_VALUE) ? 0 : nanoAppHandle + 1;
+ break;
+ }
+ nanoAppHandle = (nanoAppHandle == Integer.MAX_VALUE) ? 0 : nanoAppHandle + 1;
+ }
+
+ if (ENABLE_LOG_DEBUG) {
+ Log.v(TAG, "Added app instance with handle " + nanoAppHandle + " to hub "
+ + contextHubId + ": ID=0x" + Long.toHexString(nanoAppId)
+ + ", version=0x" + Integer.toHexString(nanoAppVersion));
+ }
+ }
+
+ /**
+ * Removes a nanoapp instance from the cache.
+ *
+ * @param nanoAppId the ID of the nanoapp to remove the instance of
+ */
+ /* package */
+ synchronized void removeNanoAppInstance(int contextHubId, long nanoAppId) {
+ int nanoAppHandle = getNanoAppHandle(contextHubId, nanoAppId);
+ mNanoAppHash.remove(nanoAppHandle);
+ }
+
+ /**
+ * Performs a batch update of the nanoapp cache given a nanoapp query response.
+ *
+ * @param contextHubId the ID of the hub the response came from
+ * @param nanoAppInfoList the list of loaded nanoapps
+ */
+ /* package */
+ synchronized void updateCache(int contextHubId, List<HubAppInfo> nanoAppInfoList) {
+ HashSet<Long> nanoAppIdSet = new HashSet<>();
+ for (HubAppInfo appInfo : nanoAppInfoList) {
+ handleQueryAppEntry(contextHubId, appInfo.appId, appInfo.version);
+ nanoAppIdSet.add(appInfo.appId);
+ }
+
+ for (int nanoAppHandle : mNanoAppHash.keySet()) {
+ NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppHandle);
+ if (info.getContexthubId() == contextHubId &&
+ !nanoAppIdSet.contains(info.getAppId())) {
+ mNanoAppHash.remove(nanoAppHandle);
+ }
+ }
+ }
+
+ /**
+ * If the nanoapp exists in the cache, then the entry is updated. Otherwise, inserts a new
+ * instance of the nanoapp in the cache. This method should only be invoked from updateCache.
+ *
+ * @param contextHubId the ID of the hub the nanoapp is loaded in
+ * @param nanoAppId the unique 64-bit ID of the nanoapp
+ * @param nanoAppVersion the version of the nanoapp
+ */
+ private void handleQueryAppEntry(int contextHubId, long nanoAppId, int nanoAppVersion) {
+ int nanoAppHandle = getNanoAppHandle(contextHubId, nanoAppId);
+ if (nanoAppHandle == -1) {
+ addNanoAppInstance(contextHubId, nanoAppId, nanoAppVersion);
+ } else {
+ NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppHandle);
+ if (info.getAppVersion() != nanoAppVersion) {
+ mNanoAppHash.put(nanoAppHandle, new NanoAppInstanceInfo(
+ nanoAppHandle, nanoAppId, nanoAppVersion, contextHubId));
+ if (ENABLE_LOG_DEBUG) {
+ Log.v(TAG, "Updated app instance with handle " + nanoAppHandle + " at hub "
+ + contextHubId + ": ID=0x" + Long.toHexString(nanoAppId)
+ + ", version=0x" + Integer.toHexString(nanoAppVersion));
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java
index f51bc87..58a9516 100644
--- a/services/core/java/com/android/server/location/RemoteListenerHelper.java
+++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java
@@ -16,8 +16,6 @@
package com.android.server.location;
-import com.android.internal.util.Preconditions;
-
import android.annotation.NonNull;
import android.os.Handler;
import android.os.IBinder;
@@ -25,7 +23,8 @@
import android.os.RemoteException;
import android.util.Log;
-import java.lang.Runnable;
+import com.android.internal.util.Preconditions;
+
import java.util.HashMap;
import java.util.Map;
@@ -40,6 +39,7 @@
protected static final int RESULT_GPS_LOCATION_DISABLED = 3;
protected static final int RESULT_INTERNAL_ERROR = 4;
protected static final int RESULT_UNKNOWN = 5;
+ protected static final int RESULT_NOT_ALLOWED = 6;
private final Handler mHandler;
private final String mTag;
@@ -118,7 +118,8 @@
protected abstract boolean isAvailableInPlatform();
protected abstract boolean isGpsEnabled();
- protected abstract boolean registerWithService(); // must access only on handler thread
+ // must access only on handler thread
+ protected abstract int registerWithService();
protected abstract void unregisterFromService(); // must access only on handler thread
protected abstract ListenerOperation<TListener> getHandlerOperation(int result);
@@ -177,10 +178,12 @@
private void tryRegister() {
mHandler.post(new Runnable() {
+ int registrationState = RESULT_INTERNAL_ERROR;
@Override
public void run() {
if (!mIsRegistered) {
- mIsRegistered = registerWithService();
+ registrationState = registerWithService();
+ mIsRegistered = registrationState == RESULT_SUCCESS;
}
if (!mIsRegistered) {
// post back a failure
@@ -188,7 +191,7 @@
@Override
public void run() {
synchronized (mListenerMap) {
- ListenerOperation<TListener> operation = getHandlerOperation(RESULT_INTERNAL_ERROR);
+ ListenerOperation<TListener> operation = getHandlerOperation(registrationState);
foreachUnsafe(operation);
}
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java
new file mode 100644
index 0000000..40c7889
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java
@@ -0,0 +1,133 @@
+/*
+ * 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.locksettings.recoverablekeystore;
+
+import android.security.keystore.AndroidKeyStoreSecretKey;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
+import android.util.Log;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableEntryException;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.security.auth.DestroyFailedException;
+
+/**
+ * Generates keys and stores them both in AndroidKeyStore and on disk, in wrapped form.
+ *
+ * <p>Generates 256-bit AES keys, which can be used for encrypt / decrypt with AES/GCM/NoPadding.
+ * They are synced to disk wrapped by a platform key. This allows them to be exported to a remote
+ * service.
+ *
+ * @hide
+ */
+public class RecoverableKeyGenerator {
+ private static final String TAG = "RecoverableKeyGenerator";
+ private static final String KEY_GENERATOR_ALGORITHM = "AES";
+ private static final int KEY_SIZE_BITS = 256;
+
+ /**
+ * A new {@link RecoverableKeyGenerator} instance.
+ *
+ * @param platformKey Secret key used to wrap generated keys before persisting to disk.
+ * @param recoverableKeyStorage Class that manages persisting wrapped keys to disk.
+ * @throws NoSuchAlgorithmException if "AES" key generation or "AES/GCM/NoPadding" cipher is
+ * unavailable. Should never happen.
+ *
+ * @hide
+ */
+ public static RecoverableKeyGenerator newInstance(
+ AndroidKeyStoreSecretKey platformKey, RecoverableKeyStorage recoverableKeyStorage)
+ throws NoSuchAlgorithmException {
+ // NB: This cannot use AndroidKeyStore as the provider, as we need access to the raw key
+ // material, so that it can be synced to disk in encrypted form.
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_GENERATOR_ALGORITHM);
+ return new RecoverableKeyGenerator(keyGenerator, platformKey, recoverableKeyStorage);
+ }
+
+ private final KeyGenerator mKeyGenerator;
+ private final RecoverableKeyStorage mRecoverableKeyStorage;
+ private final AndroidKeyStoreSecretKey mPlatformKey;
+
+ private RecoverableKeyGenerator(
+ KeyGenerator keyGenerator,
+ AndroidKeyStoreSecretKey platformKey,
+ RecoverableKeyStorage recoverableKeyStorage) {
+ mKeyGenerator = keyGenerator;
+ mRecoverableKeyStorage = recoverableKeyStorage;
+ mPlatformKey = platformKey;
+ }
+
+ /**
+ * Generates a 256-bit AES key with the given alias.
+ *
+ * <p>Stores in the AndroidKeyStore, as well as persisting in wrapped form to disk. It is
+ * persisted to disk so that it can be synced remotely, and then recovered on another device.
+ * The generated key allows encrypt/decrypt only using AES/GCM/NoPadding.
+ *
+ * <p>The key handle returned to the caller is a reference to the AndroidKeyStore key,
+ * meaning that the caller is never able to access the raw, unencrypted key.
+ *
+ * @param alias The alias by which the key will be known in AndroidKeyStore.
+ * @throws InvalidKeyException if the platform key cannot be used to wrap keys.
+ * @throws IOException if there was an issue writing the wrapped key to the wrapped key store.
+ * @throws UnrecoverableEntryException if could not retrieve key after putting it in
+ * AndroidKeyStore. This should not happen.
+ * @return A handle to the AndroidKeyStore key.
+ *
+ * @hide
+ */
+ public SecretKey generateAndStoreKey(String alias) throws KeyStoreException,
+ InvalidKeyException, IOException, UnrecoverableEntryException {
+ mKeyGenerator.init(KEY_SIZE_BITS);
+ SecretKey key = mKeyGenerator.generateKey();
+
+ mRecoverableKeyStorage.importIntoAndroidKeyStore(
+ alias,
+ key,
+ new KeyProtection.Builder(
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .build());
+ WrappedKey wrappedKey = WrappedKey.fromSecretKey(mPlatformKey, key);
+
+ try {
+ // Keep raw key material in memory for minimum possible time.
+ key.destroy();
+ } catch (DestroyFailedException e) {
+ Log.w(TAG, "Could not destroy SecretKey.");
+ }
+
+ mRecoverableKeyStorage.persistToDisk(alias, wrappedKey);
+
+ try {
+ // Reload from the keystore, so that the caller is only provided with the handle of the
+ // key, not the raw key material.
+ return mRecoverableKeyStorage.loadFromAndroidKeyStore(alias);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(
+ "Impossible: NoSuchAlgorithmException when attempting to retrieve a key "
+ + "that has only just been stored in AndroidKeyStore.", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStorage.java
new file mode 100644
index 0000000..cd85a97
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStorage.java
@@ -0,0 +1,71 @@
+/*
+ * 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.locksettings.recoverablekeystore;
+
+import android.security.keystore.KeyProtection;
+
+import java.io.IOException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableEntryException;
+
+import javax.crypto.SecretKey;
+
+/**
+ * Stores wrapped keys to disk, so they can be synced on the next screen unlock event.
+ *
+ * @hide
+ */
+public interface RecoverableKeyStorage {
+
+ /**
+ * Writes {@code wrappedKey} to disk, keyed by the application's uid and the {@code alias}.
+ *
+ * @throws IOException if an error occurred writing to disk.
+ *
+ * @hide
+ */
+ void persistToDisk(String alias, WrappedKey wrappedKey) throws IOException;
+
+ /**
+ * Imports {@code key} into AndroidKeyStore, keyed by the application's uid and
+ * the {@code alias}.
+ *
+ * @param alias The alias of the key.
+ * @param key The key.
+ * @param keyProtection Protection params denoting what the key can be used for. (e.g., what
+ * Cipher modes, whether for encrpyt/decrypt or signing, etc.)
+ * @throws KeyStoreException if an error occurred loading the key into the AndroidKeyStore.
+ *
+ * @hide
+ */
+ void importIntoAndroidKeyStore(String alias, SecretKey key, KeyProtection keyProtection) throws
+ KeyStoreException;
+
+ /**
+ * Loads a key handle from AndroidKeyStore.
+ *
+ * @param alias Alias of the key to load.
+ * @return The key handle.
+ * @throws KeyStoreException if an error occurred loading the key from AndroidKeyStore.
+ *
+ * @hide
+ */
+ SecretKey loadFromAndroidKeyStore(String alias) throws KeyStoreException,
+ NoSuchAlgorithmException,
+ UnrecoverableEntryException;
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStorageImpl.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStorageImpl.java
new file mode 100644
index 0000000..4e0751b
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStorageImpl.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.server.locksettings.recoverablekeystore;
+
+import android.security.keystore.KeyProtection;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableEntryException;
+import java.security.cert.CertificateException;
+
+import javax.crypto.SecretKey;
+
+/**
+ * Implementation of {@link RecoverableKeyStorage}.
+ *
+ * <p>Persists wrapped keys to disk, and loads raw keys into AndroidKeyStore.
+ *
+ * @hide
+ */
+public class RecoverableKeyStorageImpl implements RecoverableKeyStorage {
+ private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
+
+ private final KeyStore mKeyStore;
+
+ /**
+ * A new instance.
+ *
+ * @throws KeyStoreException if unable to load AndroidKeyStore.
+ *
+ * @hide
+ */
+ public static RecoverableKeyStorageImpl newInstance() throws KeyStoreException {
+ KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
+ try {
+ keyStore.load(/*param=*/ null);
+ } catch (CertificateException | IOException | NoSuchAlgorithmException e) {
+ // Should never happen.
+ throw new KeyStoreException("Unable to load keystore.", e);
+ }
+ return new RecoverableKeyStorageImpl(keyStore);
+ }
+
+ private RecoverableKeyStorageImpl(KeyStore keyStore) {
+ mKeyStore = keyStore;
+ }
+
+ /**
+ * Writes {@code wrappedKey} to disk, keyed by the application's uid and the {@code alias}.
+ *
+ * @throws IOException if an error occurred writing to disk.
+ *
+ * @hide
+ */
+ @Override
+ public void persistToDisk(String alias, WrappedKey wrappedKey) throws IOException {
+ // TODO(robertberry) Add implementation.
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Imports {@code key} into AndroidKeyStore, keyed by the application's uid and the
+ * {@code alias}.
+ *
+ * @param alias The alias of the key.
+ * @param key The key.
+ * @param keyProtection Protection params denoting what the key can be used for. (e.g., what
+ * Cipher modes, whether for encrpyt/decrypt or signing, etc.)
+ * @throws KeyStoreException if an error occurred loading the key into the AndroidKeyStore.
+ *
+ * @hide
+ */
+ @Override
+ public void importIntoAndroidKeyStore(String alias, SecretKey key, KeyProtection keyProtection)
+ throws KeyStoreException {
+ mKeyStore.setEntry(alias, new KeyStore.SecretKeyEntry(key), keyProtection);
+ }
+
+ /**
+ * Loads a key handle from AndroidKeyStore.
+ *
+ * @param alias Alias of the key to load.
+ * @return The key handle.
+ * @throws KeyStoreException if an error occurred loading the key from AndroidKeyStore.
+ *
+ * @hide
+ */
+ @Override
+ public SecretKey loadFromAndroidKeyStore(String alias)
+ throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableEntryException {
+ return ((KeyStore.SecretKeyEntry) mKeyStore.getEntry(alias, /*protParam=*/ null))
+ .getSecretKey();
+ }
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
new file mode 100644
index 0000000..c97c66e
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.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 com.android.server.locksettings.recoverablekeystore;
+
+import java.security.InvalidKeyException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+
+/**
+ * A {@link javax.crypto.SecretKey} wrapped with AES/GCM/NoPadding.
+ *
+ * @hide
+ */
+public class WrappedKey {
+ private static final String KEY_WRAP_CIPHER_ALGORITHM = "AES/GCM/NoPadding";
+
+ private final byte[] mNonce;
+ private final byte[] mKeyMaterial;
+
+ /**
+ * Returns a wrapped form of {@code key}, using {@code wrappingKey} to encrypt the key material.
+ *
+ * @throws InvalidKeyException if {@code wrappingKey} cannot be used to encrypt {@code key}, or
+ * if {@code key} does not expose its key material. See
+ * {@link android.security.keystore.AndroidKeyStoreKey} for an example of a key that does
+ * not expose its key material.
+ */
+ public static WrappedKey fromSecretKey(
+ SecretKey wrappingKey, SecretKey key) throws InvalidKeyException, KeyStoreException {
+ if (key.getEncoded() == null) {
+ throw new InvalidKeyException(
+ "key does not expose encoded material. It cannot be wrapped.");
+ }
+
+ Cipher cipher;
+ try {
+ cipher = Cipher.getInstance(KEY_WRAP_CIPHER_ALGORITHM);
+ } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
+ throw new RuntimeException(
+ "Android does not support AES/GCM/NoPadding. This should never happen.");
+ }
+
+ cipher.init(Cipher.WRAP_MODE, wrappingKey);
+ byte[] encryptedKeyMaterial;
+ try {
+ encryptedKeyMaterial = cipher.wrap(key);
+ } catch (IllegalBlockSizeException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof KeyStoreException) {
+ // If AndroidKeyStore encounters any error here, it throws IllegalBlockSizeException
+ // with KeyStoreException as the cause. This is due to there being no better option
+ // here, as the Cipher#wrap only checked throws InvalidKeyException or
+ // IllegalBlockSizeException. If this is the case, we want to propagate it to the
+ // caller, so rethrow the cause.
+ throw (KeyStoreException) cause;
+ } else {
+ throw new RuntimeException(
+ "IllegalBlockSizeException should not be thrown by AES/GCM/NoPadding mode.",
+ e);
+ }
+ }
+
+ return new WrappedKey(/*mNonce=*/ cipher.getIV(), /*mKeyMaterial=*/ encryptedKeyMaterial);
+ }
+
+ /**
+ * A new instance.
+ *
+ * @param nonce The nonce with which the key material was encrypted.
+ * @param keyMaterial The encrypted bytes of the key material.
+ *
+ * @hide
+ */
+ public WrappedKey(byte[] nonce, byte[] keyMaterial) {
+ mNonce = nonce;
+ mKeyMaterial = keyMaterial;
+ }
+
+ /**
+ * Returns the nonce with which the key material was encrypted.
+ *
+ * @hide
+ */
+ public byte[] getNonce() {
+ return mNonce;
+ }
+
+ /**
+ * Returns the encrypted key material.
+ *
+ * @hide
+ */
+ public byte[] getKeyMaterial() {
+ return mKeyMaterial;
+ }
+}
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/net/OWNERS b/services/core/java/com/android/server/net/OWNERS
index 6b77d83..5d4287b 100644
--- a/services/core/java/com/android/server/net/OWNERS
+++ b/services/core/java/com/android/server/net/OWNERS
@@ -2,6 +2,7 @@
ek@google.com
hugobenichi@google.com
+jchalard@google.com
jsharkey@android.com
lorenzo@google.com
satk@google.com
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/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 2940a6e..2041de6 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -370,10 +370,10 @@
false);
if (pi != null) {
mPackageManager.cachePackageInfo(packageName, userId, pi);
- if (!isOverlayPackage(pi)) {
- mImpl.onTargetPackageAdded(packageName, userId);
- } else {
+ if (pi.isOverlayPackage()) {
mImpl.onOverlayPackageAdded(packageName, userId);
+ } else {
+ mImpl.onTargetPackageAdded(packageName, userId);
}
}
}
@@ -388,10 +388,10 @@
false);
if (pi != null) {
mPackageManager.cachePackageInfo(packageName, userId, pi);
- if (!isOverlayPackage(pi)) {
- mImpl.onTargetPackageChanged(packageName, userId);
- } else {
+ if (pi.isOverlayPackage()) {
mImpl.onOverlayPackageChanged(packageName, userId);
+ } else {
+ mImpl.onTargetPackageChanged(packageName, userId);
}
}
}
@@ -404,10 +404,10 @@
synchronized (mLock) {
mPackageManager.forgetPackageInfo(packageName, userId);
final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
- if (oi == null) {
- mImpl.onTargetPackageUpgrading(packageName, userId);
- } else {
+ if (oi != null) {
mImpl.onOverlayPackageUpgrading(packageName, userId);
+ } else {
+ mImpl.onTargetPackageUpgrading(packageName, userId);
}
}
}
@@ -421,10 +421,10 @@
false);
if (pi != null) {
mPackageManager.cachePackageInfo(packageName, userId, pi);
- if (!isOverlayPackage(pi)) {
- mImpl.onTargetPackageUpgraded(packageName, userId);
- } else {
+ if (pi.isOverlayPackage()) {
mImpl.onOverlayPackageUpgraded(packageName, userId);
+ } else {
+ mImpl.onTargetPackageUpgraded(packageName, userId);
}
}
}
@@ -437,10 +437,10 @@
synchronized (mLock) {
mPackageManager.forgetPackageInfo(packageName, userId);
final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
- if (oi == null) {
- mImpl.onTargetPackageRemoved(packageName, userId);
- } else {
+ if (oi != null) {
mImpl.onOverlayPackageRemoved(packageName, userId);
+ } else {
+ mImpl.onTargetPackageRemoved(packageName, userId);
}
}
}
@@ -668,10 +668,6 @@
}
};
- private boolean isOverlayPackage(@NonNull final PackageInfo pi) {
- return pi != null && pi.overlayTarget != null;
- }
-
private final class OverlayChangeListener
implements OverlayManagerServiceImpl.OverlayChangeListener {
@Override
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index db6e974..253d4f5 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -102,11 +102,11 @@
mSettings.init(overlayPackage.packageName, newUserId,
overlayPackage.overlayTarget,
overlayPackage.applicationInfo.getBaseCodePath(),
- overlayPackage.isStaticOverlay, overlayPackage.overlayPriority);
+ overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority);
if (oi == null) {
// This overlay does not exist in our settings.
- if (overlayPackage.isStaticOverlay ||
+ if (overlayPackage.isStaticOverlayPackage() ||
mDefaultOverlays.contains(overlayPackage.packageName)) {
// Enable this overlay by default.
if (DEBUG) {
@@ -255,8 +255,8 @@
mPackageManager.getPackageInfo(overlayPackage.overlayTarget, userId);
mSettings.init(packageName, userId, overlayPackage.overlayTarget,
- overlayPackage.applicationInfo.getBaseCodePath(), overlayPackage.isStaticOverlay,
- overlayPackage.overlayPriority);
+ overlayPackage.applicationInfo.getBaseCodePath(),
+ overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority);
try {
if (updateState(targetPackage, overlayPackage, userId)) {
mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
@@ -313,7 +313,7 @@
}
// Ignore static overlays.
- if (overlayPackage.isStaticOverlay) {
+ if (overlayPackage.isStaticOverlayPackage()) {
return false;
}
@@ -363,7 +363,7 @@
continue;
}
- if (disabledOverlayPackageInfo.isStaticOverlay) {
+ if (disabledOverlayPackageInfo.isStaticOverlayPackage()) {
// Don't touch static overlays.
continue;
}
@@ -388,7 +388,7 @@
private boolean isPackageUpdatableOverlay(@NonNull final String packageName, final int userId) {
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
- if (overlayPackage == null || overlayPackage.isStaticOverlay) {
+ if (overlayPackage == null || overlayPackage.isStaticOverlayPackage()) {
return false;
}
return true;
@@ -483,7 +483,8 @@
throws OverlayManagerSettings.BadKeyException {
// Static RROs targeting to "android", ie framework-res.apk, are handled by native layers.
if (targetPackage != null &&
- !("android".equals(targetPackage.packageName) && overlayPackage.isStaticOverlay)) {
+ !("android".equals(targetPackage.packageName)
+ && overlayPackage.isStaticOverlayPackage())) {
mIdmapManager.createIdmap(targetPackage, overlayPackage, userId);
}
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 2d5f7c7..f106391 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -47,6 +47,7 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
+import static android.content.pm.PackageManager.INSTALL_FAILED_NEWER_SDK;
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
import static android.content.pm.PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
import static android.content.pm.PackageManager.INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE;
@@ -111,7 +112,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 +187,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 +243,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 +266,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 +292,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 +308,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 +335,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 +354,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 +457,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,
@@ -617,6 +608,12 @@
*/
private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = true;
+ /**
+ * Permissions required in order to receive instant application lifecycle broadcasts.
+ */
+ private static final String[] INSTANT_APP_BROADCAST_PERMISSION =
+ new String[] { android.Manifest.permission.ACCESS_INSTANT_APPS };
+
final ServiceThread mHandlerThread;
final PackageHandler mHandler;
@@ -887,8 +884,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(
@@ -897,8 +894,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.
@@ -938,6 +935,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).
@@ -1975,16 +1974,20 @@
// Determine the set of users who are adding this package for
// the first time vs. those who are seeing an update.
- int[] firstUsers = EMPTY_INT_ARRAY;
- int[] updateUsers = EMPTY_INT_ARRAY;
+ int[] firstUserIds = EMPTY_INT_ARRAY;
+ int[] firstInstantUserIds = EMPTY_INT_ARRAY;
+ int[] updateUserIds = EMPTY_INT_ARRAY;
+ int[] instantUserIds = EMPTY_INT_ARRAY;
final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0;
final PackageSetting ps = (PackageSetting) res.pkg.mExtras;
for (int newUser : res.newUsers) {
- if (ps.getInstantApp(newUser)) {
- continue;
- }
+ final boolean isInstantApp = ps.getInstantApp(newUser);
if (allNewUsers) {
- firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
+ if (isInstantApp) {
+ firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
+ } else {
+ firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
+ }
continue;
}
boolean isNew = true;
@@ -1995,9 +1998,17 @@
}
}
if (isNew) {
- firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
+ if (isInstantApp) {
+ firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
+ } else {
+ firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
+ }
} else {
- updateUsers = ArrayUtils.appendInt(updateUsers, newUser);
+ if (isInstantApp) {
+ instantUserIds = ArrayUtils.appendInt(instantUserIds, newUser);
+ } else {
+ updateUserIds = ArrayUtils.appendInt(updateUserIds, newUser);
+ }
}
}
@@ -2010,7 +2021,7 @@
int appId = UserHandle.getAppId(res.uid);
boolean isSystem = res.pkg.applicationInfo.isSystemApp();
sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
- virtualPreload /*startReceiver*/, appId, firstUsers);
+ virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds);
// Send added for users that don't see the package for the first time
Bundle extras = new Bundle(1);
@@ -2020,11 +2031,13 @@
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
- null /*targetPackage*/, null /*finishedReceiver*/, updateUsers);
+ null /*targetPackage*/, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds);
if (installerPackageName != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
- installerPackageName, null /*finishedReceiver*/, updateUsers);
+ installerPackageName, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds);
}
// Send replaced for users that don't see the package for the first time
@@ -2032,24 +2045,26 @@
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
packageName, extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
- updateUsers);
+ updateUserIds, instantUserIds);
if (installerPackageName != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, 0 /*flags*/,
- installerPackageName, null /*finishedReceiver*/, updateUsers);
+ installerPackageName, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds);
}
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null /*package*/, null /*extras*/, 0 /*flags*/,
packageName /*targetPackage*/,
- null /*finishedReceiver*/, updateUsers);
+ null /*finishedReceiver*/, updateUserIds, instantUserIds);
} else if (launchedForRestore && !isSystemApp(res.pkg)) {
// First-install and we did a restore, so we're responsible for the
// first-launch broadcast.
if (DEBUG_BACKUP) {
Slog.i(TAG, "Post-restore of " + packageName
- + " sending FIRST_LAUNCH in " + Arrays.toString(firstUsers));
+ + " sending FIRST_LAUNCH in " + Arrays.toString(firstUserIds));
}
- sendFirstLaunchBroadcast(packageName, installerPackage, firstUsers);
+ sendFirstLaunchBroadcast(packageName, installerPackage,
+ firstUserIds, firstInstantUserIds);
}
// Send broadcast package appeared if forward locked/external for all users
@@ -2067,9 +2082,9 @@
}
// Work that needs to happen on first install within each user
- if (firstUsers != null && firstUsers.length > 0) {
+ if (firstUserIds != null && firstUserIds.length > 0) {
synchronized (mPackages) {
- for (int userId : firstUsers) {
+ for (int userId : firstUserIds) {
// If this app is a browser and it's newly-installed for some
// users, clear any default-browser state in those users. The
// app's nature doesn't depend on the user, so we can just check
@@ -2107,7 +2122,7 @@
// should not change.
// Don't notify the manager for ephemeral apps as they are not expected to
// survive long enough to benefit of background optimizations.
- for (int userId : firstUsers) {
+ for (int userId : firstUserIds) {
PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
// There's a race currently where some install events may interleave with an uninstall.
// This can lead to package info being null (b/36642664).
@@ -2574,8 +2589,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) {
@@ -2585,7 +2617,8 @@
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
- | SCAN_AS_SYSTEM,
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR,
0);
// Collect all OEM packages.
@@ -2642,7 +2675,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);
}
@@ -2770,13 +2803,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 |
@@ -3018,6 +3061,7 @@
}
mInstallerService = new PackageInstallerService(context, this);
+ mArtManagerService = new ArtManagerService(this, mInstaller, mInstallLock);
final Pair<ComponentName, String> instantAppResolverComponent =
getInstantAppResolverLPr();
if (instantAppResolverComponent != null) {
@@ -3830,7 +3874,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);
}
/**
@@ -3839,7 +3883,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);
@@ -4036,7 +4080,7 @@
if (index < 0) {
continue;
}
- if (uidPs.pkg.usesStaticLibrariesVersions[index] == libEntry.info.getVersion()) {
+ if (uidPs.pkg.usesStaticLibrariesVersions[index] == libEntry.info.getLongVersion()) {
return false;
}
}
@@ -4432,7 +4476,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;
}
@@ -4449,7 +4494,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.
@@ -4460,7 +4506,7 @@
packagesToDelete = new ArrayList<>();
}
packagesToDelete.add(new VersionedPackage(internalPackageName,
- declaringPackage.getVersionCode()));
+ declaringPackage.getLongVersionCode()));
}
}
}
@@ -4470,7 +4516,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) {
@@ -4775,7 +4821,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;
}
@@ -4799,7 +4845,7 @@
}
SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getName(),
- libInfo.getVersion(), libInfo.getType(),
+ libInfo.getLongVersion(), libInfo.getType(),
libInfo.getDeclaringPackage(), getPackagesUsingSharedLibraryLPr(libInfo,
flags, userId));
@@ -4835,7 +4881,7 @@
if (libIdx < 0) {
continue;
}
- if (ps.usesStaticLibrariesVersions[libIdx] != libInfo.getVersion()) {
+ if (ps.usesStaticLibrariesVersions[libIdx] != libInfo.getLongVersion()) {
continue;
}
if (versionedPackages == null) {
@@ -4916,7 +4962,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;
}
@@ -8335,18 +8381,25 @@
} else {
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.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 " + pkg.codePath
+ " ignored: updated version " + ps.versionCode
- + " better than this " + pkg.mVersionCode);
+ + " 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 " + updatedPs.codePathString
@@ -8358,7 +8411,7 @@
updatedPs.resourcePathString = pkg.codePath;
}
updatedPs.pkg = pkg;
- updatedPs.versionCode = pkg.mVersionCode;
+ updatedPs.versionCode = pkg.getLongVersionCode();
// Update the disabled system child packages to point to the package too.
final int childCount = updatedPs.childPackageNames != null
@@ -8369,7 +8422,7 @@
childPackageName);
if (updatedChildPkg != null) {
updatedChildPkg.pkg = pkg;
- updatedChildPkg.versionCode = pkg.mVersionCode;
+ updatedChildPkg.versionCode = pkg.getLongVersionCode();
}
}
} else {
@@ -8387,7 +8440,7 @@
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),
@@ -8440,9 +8493,9 @@
}
pkg.mExtras = updatedPs;
- throw new PackageManagerException(Log.WARN, "Package " + ps.name + " at "
- + pkg.codePath + " 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) {
@@ -8455,11 +8508,17 @@
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 ((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
@@ -8491,11 +8550,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 " + pkg.codePath
- + " but new version " + pkg.mVersionCode + " better than installed "
- + ps.versionCode + "; hiding system");
+ + " but new version " + pkg.getLongVersionCode()
+ + " better than installed " + ps.versionCode + "; hiding system");
} else {
/*
* The newly found system app is a newer version that the
@@ -8505,7 +8564,8 @@
*/
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) {
@@ -9083,12 +9143,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) {
@@ -9097,7 +9157,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) {
@@ -9107,8 +9167,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;
}
@@ -9116,15 +9176,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);
}
@@ -9408,14 +9468,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) {
@@ -9430,11 +9490,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);
@@ -9458,7 +9518,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
@@ -9677,6 +9737,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) {
@@ -9754,11 +9815,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;
}
}
@@ -9793,7 +9857,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(),
@@ -9974,7 +10038,7 @@
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, cpuAbiOverride, extractNativeLibs, mAppLib32InstallDir);
@@ -10208,6 +10272,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;
@@ -10357,20 +10425,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;
@@ -10378,7 +10446,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");
}
@@ -10468,11 +10537,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);
@@ -10486,8 +10555,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;
}
@@ -10526,6 +10595,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;
@@ -10567,7 +10637,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 "
@@ -10613,7 +10683,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");
}
@@ -12730,9 +12800,10 @@
}
};
+ @Override
public void sendPackageBroadcast(final String action, final String pkg, final Bundle extras,
final int flags, final String targetPkg, final IIntentReceiver finishedReceiver,
- final int[] userIds) {
+ final int[] userIds, int[] instantUserIds) {
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -12745,33 +12816,11 @@
} else {
resolvedUserIds = userIds;
}
- for (int id : resolvedUserIds) {
- final Intent intent = new Intent(action,
- pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null) : null);
- if (extras != null) {
- intent.putExtras(extras);
- }
- if (targetPkg != null) {
- intent.setPackage(targetPkg);
- }
- // Modify the UID when posting to other users
- int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- if (uid > 0 && UserHandle.getUserId(uid) != id) {
- uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
- intent.putExtra(Intent.EXTRA_UID, uid);
- }
- intent.putExtra(Intent.EXTRA_USER_HANDLE, id);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | flags);
- if (DEBUG_BROADCASTS) {
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
- Slog.d(TAG, "Sending to user " + id + ": "
- + intent.toShortString(false, true, false, false)
- + " " + intent.getExtras(), here);
- }
- am.broadcastIntent(null, intent, null, finishedReceiver,
- 0, null, null, null, android.app.AppOpsManager.OP_NONE,
- null, finishedReceiver != null, false, id);
+ doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
+ resolvedUserIds, false);
+ if (instantUserIds != null && instantUserIds != EMPTY_INT_ARRAY) {
+ doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
+ instantUserIds, true);
}
} catch (RemoteException ex) {
}
@@ -12780,6 +12829,49 @@
}
/**
+ * Sends a broadcast for the given action.
+ * <p>If {@code isInstantApp} is {@code true}, then the broadcast is protected with
+ * the {@link android.Manifest.permission#ACCESS_INSTANT_APPS} permission. This allows
+ * the system and applications allowed to see instant applications to receive package
+ * lifecycle events for instant applications.
+ */
+ private void doSendBroadcast(IActivityManager am, String action, String pkg, Bundle extras,
+ int flags, String targetPkg, IIntentReceiver finishedReceiver,
+ int[] userIds, boolean isInstantApp)
+ throws RemoteException {
+ for (int id : userIds) {
+ final Intent intent = new Intent(action,
+ pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null) : null);
+ final String[] requiredPermissions =
+ isInstantApp ? INSTANT_APP_BROADCAST_PERMISSION : null;
+ if (extras != null) {
+ intent.putExtras(extras);
+ }
+ if (targetPkg != null) {
+ intent.setPackage(targetPkg);
+ }
+ // Modify the UID when posting to other users
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ if (uid > 0 && UserHandle.getUserId(uid) != id) {
+ uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
+ intent.putExtra(Intent.EXTRA_UID, uid);
+ }
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, id);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | flags);
+ if (DEBUG_BROADCASTS) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.d(TAG, "Sending to user " + id + ": "
+ + intent.toShortString(false, true, false, false)
+ + " " + intent.getExtras(), here);
+ }
+ am.broadcastIntent(null, intent, null, finishedReceiver,
+ 0, null, null, requiredPermissions, android.app.AppOpsManager.OP_NONE,
+ null, finishedReceiver != null, false, id);
+ }
+ }
+
+ /**
* Check if the external storage media is available. This is true if there
* is a mounted external storage medium or if the external storage is
* emulated.
@@ -12793,14 +12885,13 @@
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return null;
}
- // writer
- synchronized (mPackages) {
- if (!isExternalMediaAvailable()) {
+ if (!isExternalMediaAvailable()) {
// If the external storage is no longer mounted at this point,
// the caller may not have been able to delete all of this
// packages files and can not delete any more. Bail.
- return null;
- }
+ return null;
+ }
+ synchronized (mPackages) {
final ArrayList<PackageCleanItem> pkgs = mSettings.mPackagesToBeCleaned;
if (lastPackage != null) {
pkgs.remove(lastPackage);
@@ -13028,8 +13119,11 @@
private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
int userId) {
final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
+ final boolean isInstantApp = pkgSetting.getInstantApp(userId);
+ final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
+ final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
sendPackageAddedForNewUsers(packageName, isSystem /*sendBootCompleted*/,
- false /*startReceiver*/, pkgSetting.appId, userId);
+ false /*startReceiver*/, pkgSetting.appId, userIds, instantUserIds);
// Send a session commit broadcast
final PackageInstaller.SessionInfo info = new PackageInstaller.SessionInfo();
@@ -13038,18 +13132,21 @@
sendSessionCommitBroadcast(info, userId);
}
+ @Override
public void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
- boolean includeStopped, int appId, int... userIds) {
- if (ArrayUtils.isEmpty(userIds)) {
+ boolean includeStopped, int appId, int[] userIds, int[] instantUserIds) {
+ if (ArrayUtils.isEmpty(userIds) && ArrayUtils.isEmpty(instantUserIds)) {
return;
}
Bundle extras = new Bundle(1);
// Set to UID of the first user, EXTRA_UID is automatically updated in sendPackageBroadcast
- extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userIds[0], appId));
+ final int uid = UserHandle.getUid(
+ (ArrayUtils.isEmpty(userIds) ? instantUserIds[0] : userIds[0]), appId);
+ extras.putInt(Intent.EXTRA_UID, uid);
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
- packageName, extras, 0, null, null, userIds);
- if (sendBootCompleted) {
+ packageName, extras, 0, null, null, userIds, instantUserIds);
+ if (sendBootCompleted && !ArrayUtils.isEmpty(userIds)) {
mHandler.post(() -> {
for (int userId : userIds) {
sendBootCompletedBroadcastToSystemApp(
@@ -13193,7 +13290,7 @@
suspended ? Intent.ACTION_PACKAGES_SUSPENDED
: Intent.ACTION_PACKAGES_UNSUSPENDED,
null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null,
- new int[] {userId});
+ new int[] {userId}, null);
}
}
@@ -14081,7 +14178,8 @@
* the first-launch broadcast will be sent implicitly on that basis in POST_INSTALL
* handling.
*/
- void notifyFirstLaunch(final String pkgName, final String installerPackage, final int userId) {
+ void notifyFirstLaunch(final String packageName, final String installerPackage,
+ final int userId) {
// Serialize this with the rest of the install-process message chain. In the
// restore-at-install case, this Runnable will necessarily run before the
// POST_INSTALL message is processed, so the contents of mRunningInstalls
@@ -14096,12 +14194,12 @@
if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
continue;
}
- if (pkgName.equals(data.res.pkg.applicationInfo.packageName)) {
+ if (packageName.equals(data.res.pkg.applicationInfo.packageName)) {
// right package; but is it for the right user?
for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
if (userId == data.res.newUsers[uIndex]) {
if (DEBUG_BACKUP) {
- Slog.i(TAG, "Package " + pkgName
+ Slog.i(TAG, "Package " + packageName
+ " being restored so deferring FIRST_LAUNCH");
}
return;
@@ -14111,16 +14209,20 @@
}
// didn't find it, so not being restored
if (DEBUG_BACKUP) {
- Slog.i(TAG, "Package " + pkgName + " sending normal FIRST_LAUNCH");
+ Slog.i(TAG, "Package " + packageName + " sending normal FIRST_LAUNCH");
}
- sendFirstLaunchBroadcast(pkgName, installerPackage, new int[] {userId});
+ final boolean isInstantApp = isInstantApp(packageName, userId);
+ final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
+ final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
+ sendFirstLaunchBroadcast(packageName, installerPackage, userIds, instantUserIds);
}
});
}
- private void sendFirstLaunchBroadcast(String pkgName, String installerPkg, int[] userIds) {
+ private void sendFirstLaunchBroadcast(String pkgName, String installerPkg,
+ int[] userIds, int[] instantUserIds) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0,
- installerPkg, null, userIds);
+ installerPkg, null, userIds, instantUserIds);
}
private abstract class HandlerParams {
@@ -14608,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,
@@ -15493,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);
@@ -15574,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);
@@ -16166,6 +16284,16 @@
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
+ // App targetSdkVersion is below min supported version
+ if (!forceSdk && pkg.applicationInfo.isTargetingDeprecatedSdkVersion()) {
+ Slog.w(TAG, "App " + pkg.packageName + " targets deprecated sdk");
+
+ res.setError(INSTALL_FAILED_NEWER_SDK,
+ "App is targeting deprecated sdk (targetSdkVersion should be at least "
+ + Build.VERSION.MIN_SUPPORTED_TARGET_SDK_INT + ").");
+ return;
+ }
+
// Instant apps must have target SDK >= O and have targetSanboxVersion >= 2
if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
Slog.w(TAG, "Instant app package " + pkg.packageName + " does not target O");
@@ -16303,6 +16431,13 @@
+ " target SDK " + oldTargetSdk + " does.");
return;
}
+ // Prevent persistent apps from being updated
+ if ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0) {
+ res.setError(PackageManager.INSTALL_FAILED_INVALID_APK,
+ "Package " + oldPackage.packageName + " is a persistent app. "
+ + "Persistent apps are not updateable.");
+ return;
+ }
// Prevent apps from downgrading their targetSandbox.
final int oldTargetSandbox = oldPackage.applicationInfo.targetSandboxVersion;
final int newTargetSandbox = pkg.applicationInfo.targetSandboxVersion;
@@ -16508,50 +16643,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 {
@@ -16569,7 +16660,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;
@@ -16583,6 +16675,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) {
@@ -16759,6 +16900,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;
}
@@ -16823,17 +16968,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();
@@ -16941,24 +17085,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) {
@@ -16966,7 +17110,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);
}
}
@@ -16984,10 +17128,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;
@@ -16995,7 +17139,7 @@
} else if (highestVersion == null) {
highestVersion = libEntry;
} else if (libVersionCode > highestVersion.info
- .getDeclaringPackage().getVersionCode()) {
+ .getDeclaringPackage().getLongVersionCode()) {
highestVersion = libEntry;
}
}
@@ -17124,7 +17268,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;
@@ -17175,7 +17319,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;
}
@@ -17242,6 +17386,7 @@
int[] origUsers;
int[] removedUsers = null;
int[] broadcastUsers = null;
+ int[] instantUserIds = null;
SparseArray<Integer> installReasons;
boolean isRemovedPackageSystemUpdate = false;
boolean isUpdate;
@@ -17287,7 +17432,7 @@
PackageInstalledInfo installedInfo = appearedChildPackages.valueAt(i);
packageSender.sendPackageAddedForNewUsers(installedInfo.name,
true /*sendBootCompleted*/, false /*startReceiver*/,
- UserHandle.getAppId(installedInfo.uid), installedInfo.newUsers);
+ UserHandle.getAppId(installedInfo.uid), installedInfo.newUsers, null);
}
}
@@ -17296,18 +17441,18 @@
extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
- removedPackage, extras, 0, null /*targetPackage*/, null, null);
+ removedPackage, extras, 0, null /*targetPackage*/, null, null, null);
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- removedPackage, extras, 0, null /*targetPackage*/, null, null);
+ removedPackage, extras, 0, null /*targetPackage*/, null, null, null);
packageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
- null, null, 0, removedPackage, null, null);
+ null, null, 0, removedPackage, null, null, null);
if (installerPackageName != null) {
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
removedPackage, extras, 0 /*flags*/,
- installerPackageName, null, null);
+ installerPackageName, null, null, null);
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
removedPackage, extras, 0 /*flags*/,
- installerPackageName, null, null);
+ installerPackageName, null, null, null);
}
}
@@ -17328,23 +17473,24 @@
extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers);
if (removedPackage != null) {
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
- removedPackage, extras, 0, null /*targetPackage*/, null, broadcastUsers);
+ removedPackage, extras, 0, null /*targetPackage*/, null,
+ broadcastUsers, instantUserIds);
if (installerPackageName != null) {
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
removedPackage, extras, 0 /*flags*/,
- installerPackageName, null, broadcastUsers);
+ installerPackageName, null, broadcastUsers, instantUserIds);
}
if (dataRemoved && !isRemovedPackageSystemUpdate) {
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED,
removedPackage, extras,
Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
- null, null, broadcastUsers);
+ null, null, broadcastUsers, instantUserIds);
}
}
if (removedAppId >= 0) {
packageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED,
null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
- null, null, broadcastUsers);
+ null, null, broadcastUsers, instantUserIds);
}
}
@@ -17356,12 +17502,14 @@
}
broadcastUsers = EMPTY_INT_ARRAY;
+ instantUserIds = EMPTY_INT_ARRAY;
for (int i = userIds.length - 1; i >= 0; --i) {
final int userId = userIds[i];
if (deletedPackageSetting.getInstantApp(userId)) {
- continue;
+ instantUserIds = ArrayUtils.appendInt(instantUserIds, userId);
+ } else {
+ broadcastUsers = ArrayUtils.appendInt(broadcastUsers, userId);
}
- broadcastUsers = ArrayUtils.appendInt(broadcastUsers, userId);
}
}
}
@@ -17493,7 +17641,9 @@
static boolean locationIsPrivileged(String path) {
try {
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
- return path.startsWith(privilegedAppDir.getCanonicalPath());
+ 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);
}
@@ -17509,6 +17659,15 @@
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);
+ }
+ return false;
+ }
+
/*
* Tries to delete system package.
*/
@@ -17630,6 +17789,9 @@
if (locationIsOem(codePathString)) {
scanFlags |= SCAN_AS_OEM;
}
+ if (locationIsVendor(codePathString)) {
+ scanFlags |= SCAN_AS_VENDOR;
+ }
final File codePath = new File(codePathString);
final PackageParser.Package pkg =
@@ -19893,8 +20055,12 @@
// little component state change.
final int flags = !componentNames.contains(packageName)
? Intent.FLAG_RECEIVER_REGISTERED_ONLY : 0;
+ final int userId = UserHandle.getUserId(packageUid);
+ final boolean isInstantApp = isInstantApp(packageName, userId);
+ final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
+ final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, flags, null, null,
- new int[] {UserHandle.getUserId(packageUid)});
+ userIds, instantUserIds);
}
@Override
@@ -20445,7 +20611,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;
}
@@ -20465,7 +20632,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(" -> ");
@@ -20834,7 +21001,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;
}
@@ -21012,7 +21179,7 @@
}
String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
: Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
- sendPackageBroadcast(action, null, extras, 0, null, finishedReceiver, null);
+ sendPackageBroadcast(action, null, extras, 0, null, finishedReceiver, null, null);
}
}
@@ -22191,6 +22358,11 @@
return mInstallerService;
}
+ @Override
+ public IArtManager getArtManager() {
+ return mArtManagerService;
+ }
+
private boolean userNeedsBadging(int userId) {
int index = mUserNeedsBadging.indexOfKey(userId);
if (index < 0) {
@@ -22339,11 +22511,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
@@ -22530,12 +22702,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) {
}
@@ -23236,9 +23408,13 @@
}
interface PackageSender {
+ /**
+ * @param userIds User IDs where the action occurred on a full application
+ * @param instantUserIds User IDs where the action occurred on an instant application
+ */
void sendPackageBroadcast(final String action, final String pkg,
final Bundle extras, final int flags, final String targetPkg,
- final IIntentReceiver finishedReceiver, final int[] userIds);
+ final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds);
void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
- boolean includeStopped, int appId, int... userIds);
+ boolean includeStopped, int appId, int[] userIds, int[] instantUserIds);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index fb6278a..20ec9b5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -571,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
@@ -579,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..2d82c46 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);
@@ -1374,7 +1374,7 @@
}
ClearDataObserver obs = new ClearDataObserver();
- ActivityManager.getService().clearApplicationUserData(pkg, obs, userId);
+ ActivityManager.getService().clearApplicationUserData(pkg, false, obs, userId);
synchronized (obs) {
while (!obs.finished) {
try {
@@ -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 ddad677..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) {
}
}
@@ -3677,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);
@@ -3705,7 +3707,7 @@
version = parser.getAttributeValue(null, "version");
if (version != null) {
try {
- versionCode = Integer.parseInt(version);
+ versionCode = Long.parseLong(version);
} catch (NumberFormatException e) {
}
}
@@ -4421,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/ShortcutNonPersistentUser.java b/services/core/java/com/android/server/pm/ShortcutNonPersistentUser.java
new file mode 100644
index 0000000..7f6f684
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ShortcutNonPersistentUser.java
@@ -0,0 +1,98 @@
+/*
+ * 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.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import com.android.server.pm.ShortcutService.DumpFilter;
+
+import java.io.PrintWriter;
+
+/**
+ * This class holds per-user information for {@link ShortcutService} that doesn't have to be
+ * persisted and is kept in-memory.
+ *
+ * The access to it must be guarded with the shortcut manager lock.
+ */
+public class ShortcutNonPersistentUser {
+ private final ShortcutService mService;
+
+ private final int mUserId;
+
+ /**
+ * Keep track of additional packages that other parts of the system have said are
+ * allowed to access shortcuts. The key is the part of the system it came from,
+ * the value is the package name that has access. We don't persist these because
+ * at boot all relevant system services will push this data back to us they do their
+ * normal evaluation of the state of the world.
+ */
+ private final ArrayMap<String, String> mHostPackages = new ArrayMap<>();
+
+ /**
+ * Set of package name values from above.
+ */
+ private final ArraySet<String> mHostPackageSet = new ArraySet<>();
+
+ public ShortcutNonPersistentUser(ShortcutService service, int userId) {
+ mService = service;
+ mUserId = userId;
+ }
+
+ public int getUserId() {
+ return mUserId;
+ }
+
+ public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName) {
+ if (packageName != null) {
+ mHostPackages.put(type, packageName);
+ } else {
+ mHostPackages.remove(type);
+ }
+
+ mHostPackageSet.clear();
+ for (int i = 0; i < mHostPackages.size(); i++) {
+ mHostPackageSet.add(mHostPackages.valueAt(i));
+ }
+ }
+
+ public boolean hasHostPackage(@NonNull String packageName) {
+ return mHostPackageSet.contains(packageName);
+ }
+
+ public void dump(@NonNull PrintWriter pw, @NonNull String prefix, DumpFilter filter) {
+ if (filter.shouldDumpDetails()) {
+ if (mHostPackages.size() > 0) {
+ pw.print(prefix);
+ pw.print("Non-persistent: user ID:");
+ pw.println(mUserId);
+
+ pw.print(prefix);
+ pw.println(" Host packages:");
+ for (int i = 0; i < mHostPackages.size(); i++) {
+ pw.print(prefix);
+ pw.print(" ");
+ pw.print(mHostPackages.keyAt(i));
+ pw.print(": ");
+ pw.println(mHostPackages.valueAt(i));
+ }
+ pw.println();
+ }
+ }
+ }
+}
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..3d37229 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,10 +145,10 @@
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));
+ currentPackage.getLongVersionCode(), mBackupSourceVersionCode));
return ShortcutInfo.DISABLED_REASON_VERSION_LOWER;
}
return ShortcutInfo.DISABLED_REASON_NOT_DISABLED;
@@ -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..065eafd 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -280,6 +280,13 @@
private final SparseArray<ShortcutUser> mUsers = new SparseArray<>();
/**
+ * User ID -> ShortcutNonPersistentUser
+ */
+ @GuardedBy("mLock")
+ private final SparseArray<ShortcutNonPersistentUser> mShortcutNonPersistentUsers =
+ new SparseArray<>();
+
+ /**
* Max number of dynamic + manifest shortcuts that each application can have at a time.
*/
private int mMaxShortcuts;
@@ -330,7 +337,10 @@
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_UNINSTALLED_PACKAGES;
- @GuardedBy("mLock")
+ /**
+ * Note we use a fine-grained lock for {@link #mUnlockedUsers} due to b/64303666.
+ */
+ @GuardedBy("mUnlockedUsers")
final SparseBooleanArray mUnlockedUsers = new SparseBooleanArray();
// Stats
@@ -600,7 +610,7 @@
if (DEBUG) {
Slog.d(TAG, "handleUnlockUser: user=" + userId);
}
- synchronized (mLock) {
+ synchronized (mUnlockedUsers) {
mUnlockedUsers.put(userId, true);
}
@@ -628,7 +638,9 @@
synchronized (mLock) {
unloadUserLocked(userId);
- mUnlockedUsers.put(userId, false);
+ synchronized (mUnlockedUsers) {
+ mUnlockedUsers.put(userId, false);
+ }
}
}
@@ -1149,9 +1161,12 @@
// Requires mLock held, but "Locked" prefix would look weired so we just say "L".
protected boolean isUserUnlockedL(@UserIdInt int userId) {
// First, check the local copy.
- if (mUnlockedUsers.get(userId)) {
- return true;
+ synchronized (mUnlockedUsers) {
+ if (mUnlockedUsers.get(userId)) {
+ return true;
+ }
}
+
// If the local copy says the user is locked, check with AM for the actual state, since
// the user might just have been unlocked.
// Note we just don't use isUserUnlockingOrUnlocked() here, because it'll return false
@@ -1199,6 +1214,18 @@
return userPackages;
}
+ /** Return the non-persistent per-user state. */
+ @GuardedBy("mLock")
+ @NonNull
+ ShortcutNonPersistentUser getNonPersistentUserLocked(@UserIdInt int userId) {
+ ShortcutNonPersistentUser ret = mShortcutNonPersistentUsers.get(userId);
+ if (ret == null) {
+ ret = new ShortcutNonPersistentUser(this, userId);
+ mShortcutNonPersistentUsers.put(userId, ret);
+ }
+ return ret;
+ }
+
void forEachLoadedUserLocked(@NonNull Consumer<ShortcutUser> c) {
for (int i = mUsers.size() - 1; i >= 0; i--) {
c.accept(mUsers.valueAt(i));
@@ -2251,7 +2278,7 @@
return true;
}
synchronized (mLock) {
- return getUserShortcutsLocked(userId).hasHostPackage(callingPackage);
+ return getNonPersistentUserLocked(userId).hasHostPackage(callingPackage);
}
}
@@ -2375,10 +2402,7 @@
public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
int userId) {
synchronized (mLock) {
- throwIfUserLockedL(userId);
-
- final ShortcutUser user = getUserShortcutsLocked(userId);
- user.setShortcutHostPackage(type, packageName);
+ getNonPersistentUserLocked(userId).setShortcutHostPackage(type, packageName);
}
}
@@ -2739,6 +2763,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() {
@@ -3816,6 +3860,14 @@
pw.println();
}
}
+
+ for (int i = 0; i < mShortcutNonPersistentUsers.size(); i++) {
+ final ShortcutNonPersistentUser user = mShortcutNonPersistentUsers.valueAt(i);
+ if (filter.isUserMatch(user.getUserId())) {
+ user.dump(pw, " ", filter);
+ pw.println();
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 1efd765..b7247df 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -124,20 +124,6 @@
/** In-memory-cached default launcher. */
private ComponentName mCachedLauncher;
- /**
- * Keep track of additional packages that other parts of the system have said are
- * allowed to access shortcuts. The key is the part of the system it came from,
- * the value is the package name that has access. We don't persist these because
- * at boot all relevant system services will push this data back to us they do their
- * normal evaluation of the state of the world.
- */
- private final ArrayMap<String, String> mHostPackages = new ArrayMap<>();
-
- /**
- * Set of package name values from above.
- */
- private final ArraySet<String> mHostPackageSet = new ArraySet<>();
-
private String mKnownLocales;
private long mLastAppScanTime;
@@ -482,23 +468,6 @@
return mCachedLauncher;
}
- public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName) {
- if (packageName != null) {
- mHostPackages.put(type, packageName);
- } else {
- mHostPackages.remove(type);
- }
-
- mHostPackageSet.clear();
- for (int i = 0; i < mHostPackages.size(); i++) {
- mHostPackageSet.add(mHostPackages.valueAt(i));
- }
- }
-
- public boolean hasHostPackage(@NonNull String packageName) {
- return mHostPackageSet.contains(packageName);
- }
-
public void resetThrottling() {
for (int i = mPackages.size() - 1; i >= 0; i--) {
mPackages.valueAt(i).resetThrottling();
@@ -587,18 +556,6 @@
pw.print("Last known launcher: ");
pw.print(mLastKnownLauncher);
pw.println();
-
- if (mHostPackages.size() > 0) {
- pw.print(prefix);
- pw.println("Host packages:");
- for (int i = 0; i < mHostPackages.size(); i++) {
- pw.print(prefix);
- pw.print(" ");
- pw.print(mHostPackages.keyAt(i));
- pw.print(": ");
- pw.println(mHostPackages.valueAt(i));
- }
- }
}
for (int i = 0; i < mLaunchers.size(); i++) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index dbf413f..03cd4f1 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;
}
@@ -3678,8 +3702,10 @@
}
@Override
- public UserInfo createUserEvenWhenDisallowed(String name, int flags) {
- UserInfo user = createUserInternalUnchecked(name, flags, UserHandle.USER_NULL, null);
+ public UserInfo createUserEvenWhenDisallowed(String name, int flags,
+ String[] disallowedPackages) {
+ UserInfo user = createUserInternalUnchecked(name, flags, UserHandle.USER_NULL,
+ disallowedPackages);
// Keep this in sync with UserManager.createUser
if (user != null && !user.isAdmin() && !user.isDemo()) {
setUserRestriction(UserManager.DISALLOW_SMS, true, user.id);
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 7415ec3..7c75f77 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,6 +241,7 @@
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;
@@ -246,6 +249,7 @@
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;
@@ -317,11 +321,6 @@
static final int LONG_PRESS_BACK_NOTHING = 0;
static final int LONG_PRESS_BACK_GO_TO_VOICE_ASSIST = 1;
- // Number of presses needed before we induce panic press behavior on the back button
- static final int PANIC_PRESS_BACK_COUNT = 4;
- static final int PANIC_PRESS_BACK_NOTHING = 0;
- static final int PANIC_PRESS_BACK_HOME = 1;
-
// These need to match the documentation/constant in
// core/res/res/values/config.xml
static final int LONG_PRESS_HOME_NOTHING = 0;
@@ -516,7 +515,6 @@
volatile boolean mBackKeyHandled;
volatile boolean mBeganFromNonInteractive;
volatile int mPowerKeyPressCounter;
- volatile int mBackKeyPressCounter;
volatile boolean mEndCallKeyHandled;
volatile boolean mCameraGestureTriggeredDuringGoingToSleep;
volatile boolean mGoingToSleep;
@@ -578,7 +576,6 @@
int mDoublePressOnPowerBehavior;
int mTriplePressOnPowerBehavior;
int mLongPressOnBackBehavior;
- int mPanicPressOnBackBehavior;
int mShortPressOnSleepBehavior;
int mShortPressOnWindowBehavior;
volatile boolean mAwake;
@@ -604,6 +601,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.
@@ -794,16 +793,15 @@
private static final int MSG_SHOW_PICTURE_IN_PICTURE_MENU = 17;
private static final int MSG_BACK_LONG_PRESS = 18;
private static final int MSG_DISPOSE_INPUT_CONSUMER = 19;
- private static final int MSG_BACK_DELAYED_PRESS = 20;
- private static final int MSG_ACCESSIBILITY_SHORTCUT = 21;
- private static final int MSG_BUGREPORT_TV = 22;
- private static final int MSG_ACCESSIBILITY_TV = 23;
- private static final int MSG_DISPATCH_BACK_KEY_TO_AUTOFILL = 24;
- private static final int MSG_SYSTEM_KEY_PRESS = 25;
- private static final int MSG_HANDLE_ALL_APPS = 26;
- private static final int MSG_LAUNCH_ASSIST = 27;
- private static final int MSG_LAUNCH_ASSIST_LONG_PRESS = 28;
- private static final int MSG_POWER_VERY_LONG_PRESS = 29;
+ private static final int MSG_ACCESSIBILITY_SHORTCUT = 20;
+ private static final int MSG_BUGREPORT_TV = 21;
+ private static final int MSG_ACCESSIBILITY_TV = 22;
+ private static final int MSG_DISPATCH_BACK_KEY_TO_AUTOFILL = 23;
+ private static final int MSG_SYSTEM_KEY_PRESS = 24;
+ private static final int MSG_HANDLE_ALL_APPS = 25;
+ private static final int MSG_LAUNCH_ASSIST = 26;
+ private static final int MSG_LAUNCH_ASSIST_LONG_PRESS = 27;
+ private static final int MSG_POWER_VERY_LONG_PRESS = 28;
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
@@ -881,15 +879,10 @@
break;
case MSG_BACK_LONG_PRESS:
backLongPress();
- finishBackKeyPress();
break;
case MSG_DISPOSE_INPUT_CONSUMER:
disposeInputConsumer((InputConsumer) msg.obj);
break;
- case MSG_BACK_DELAYED_PRESS:
- backMultiPressAction(msg.arg1);
- finishBackKeyPress();
- break;
case MSG_ACCESSIBILITY_SHORTCUT:
accessibilityShortcutActivated();
break;
@@ -962,6 +955,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();
}
@@ -1172,14 +1168,6 @@
// Reset back key state for long press
mBackKeyHandled = false;
- // Cancel multi-press detection timeout.
- if (hasPanicPressOnBackBehavior()) {
- if (mBackKeyPressCounter != 0
- && mBackKeyPressCounter < PANIC_PRESS_BACK_COUNT) {
- mHandler.removeMessages(MSG_BACK_DELAYED_PRESS);
- }
- }
-
if (hasLongPressOnBackBehavior()) {
Message msg = mHandler.obtainMessage(MSG_BACK_LONG_PRESS);
msg.setAsynchronous(true);
@@ -1193,21 +1181,6 @@
// Cache handled state
boolean handled = mBackKeyHandled;
- if (hasPanicPressOnBackBehavior()) {
- // Check for back key panic press
- ++mBackKeyPressCounter;
-
- final long eventTime = event.getDownTime();
-
- if (mBackKeyPressCounter <= PANIC_PRESS_BACK_COUNT) {
- // This could be a multi-press. Wait a little bit longer to confirm.
- Message msg = mHandler.obtainMessage(MSG_BACK_DELAYED_PRESS,
- mBackKeyPressCounter, 0, eventTime);
- msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg, ViewConfiguration.getMultiPressTimeout());
- }
- }
-
// Reset back long press state
cancelPendingBackKeyAction();
@@ -1385,10 +1358,6 @@
}
}
- private void finishBackKeyPress() {
- mBackKeyPressCounter = 0;
- }
-
private void cancelPendingPowerKeyAction() {
if (!mPowerKeyHandled) {
mPowerKeyHandled = true;
@@ -1406,18 +1375,6 @@
}
}
- private void backMultiPressAction(int count) {
- if (count >= PANIC_PRESS_BACK_COUNT) {
- switch (mPanicPressOnBackBehavior) {
- case PANIC_PRESS_BACK_NOTHING:
- break;
- case PANIC_PRESS_BACK_HOME:
- launchHomeFromHotKey();
- break;
- }
- }
- }
-
private void powerPress(long eventTime, boolean interactive, int count) {
if (mScreenOnEarly && !mScreenOnFully) {
Slog.i(TAG, "Suppressed redundant power key press while "
@@ -1633,10 +1590,6 @@
return mLongPressOnBackBehavior != LONG_PRESS_BACK_NOTHING;
}
- private boolean hasPanicPressOnBackBehavior() {
- return mPanicPressOnBackBehavior != PANIC_PRESS_BACK_NOTHING;
- }
-
private void interceptScreenshotChord() {
if (mScreenshotChordEnabled
&& mScreenshotChordVolumeDownKeyTriggered && mScreenshotChordPowerKeyTriggered
@@ -2027,8 +1980,6 @@
mLongPressOnBackBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnBackBehavior);
- mPanicPressOnBackBehavior = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_backPanicBehavior);
mShortPressOnPowerBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_shortPressOnPowerBehavior);
@@ -2393,6 +2344,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);
@@ -4335,7 +4290,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);
@@ -4361,12 +4316,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;
}
@@ -4397,10 +4355,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;
}
@@ -4428,7 +4388,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();
@@ -4498,6 +4458,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) {
@@ -4519,7 +4487,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) {
@@ -4581,7 +4549,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;
@@ -4632,11 +4601,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);
@@ -4657,9 +4630,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);
@@ -4680,9 +4653,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);
@@ -4712,7 +4685,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();
}
@@ -4834,6 +4807,7 @@
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 requestedSysUiFl = PolicyControl.getSystemUiVisibility(win, null);
@@ -4854,6 +4828,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) {
@@ -4863,7 +4845,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)) {
@@ -4934,8 +4917,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
@@ -5012,6 +4994,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);
@@ -5019,7 +5004,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()
@@ -5097,6 +5082,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);
@@ -5167,9 +5155,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
@@ -5218,7 +5224,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.
@@ -7213,15 +7219,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() {
@@ -8247,9 +8245,6 @@
pw.print("mLongPressOnBackBehavior=");
pw.println(longPressOnBackBehaviorToString(mLongPressOnBackBehavior));
pw.print(prefix);
- pw.print("mPanicPressOnBackBehavior=");
- pw.println(panicPressOnBackBehaviorToString(mPanicPressOnBackBehavior));
- pw.print(prefix);
pw.print("mLongPressOnHomeBehavior=");
pw.println(longPressOnHomeBehaviorToString(mLongPressOnHomeBehavior));
pw.print(prefix);
@@ -8449,17 +8444,6 @@
}
}
- private static String panicPressOnBackBehaviorToString(int behavior) {
- switch (behavior) {
- case PANIC_PRESS_BACK_NOTHING:
- return "PANIC_PRESS_BACK_NOTHING";
- case PANIC_PRESS_BACK_HOME:
- return "PANIC_PRESS_BACK_HOME";
- default:
- return Integer.toString(behavior);
- }
- }
-
private static String longPressOnHomeBehaviorToString(int behavior) {
switch (behavior) {
case LONG_PRESS_HOME_NOTHING:
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 5f067d4..cfe4088 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, @Nullable Rect outsetFrame);
+ Rect stableFrame, @Nullable Rect outsetFrame, DisplayCutout displayCutout);
/**
* Retrieve the current frame of the window that has been assigned by
@@ -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;
}
@@ -1359,7 +1362,7 @@
/**
* inKeyguardRestrictedKeyInputMode
*
- * if keyguard screen is showing or in restricted key input mode (i.e. in
+ * 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.
*
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 7c234f9..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";
@@ -87,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
@@ -323,12 +339,12 @@
}
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);
@@ -338,7 +354,7 @@
// 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.
@@ -354,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();
}
/**
@@ -419,6 +456,12 @@
}
}
+ public int getGpsMode() {
+ synchronized (mLock) {
+ return mGpsMode;
+ }
+ }
+
public ArrayMap<String, String> getFileValues(boolean interactive) {
synchronized (mLock) {
return interactive ? mFilesForInteractive : mFilesForNoninteractive;
@@ -431,6 +474,12 @@
}
}
+ public String toEventLogString() {
+ synchronized (mLock) {
+ return mEventLogKeys;
+ }
+ }
+
public void dump(PrintWriter pw) {
synchronized (mLock) {
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 80bc935..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,12 +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;
@@ -32,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;
@@ -61,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) {
@@ -92,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()]);
}
/**
@@ -104,7 +144,7 @@
}
/**
- * 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);
@@ -113,6 +153,7 @@
mFileUpdater.systemReady(LocalServices.getService(ActivityManagerInternal.class)
.isRuntimeRestarted());
+ mHandler.postSystemReady();
}
private PowerManager getPowerManager() {
@@ -137,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);
}
@@ -146,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;
}
}
}
@@ -171,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.
*/
@@ -203,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);
@@ -227,12 +299,16 @@
mFileUpdater.writeFiles(fileValues);
}
+ for (Plugin p : mPlugins) {
+ p.onBatterySaverChanged(this);
+ }
+
if (sendBroadcast) {
if (enabled) {
// STOPSHIP Remove the toast.
- Toast.makeText(mContext,
- com.android.internal.R.string.battery_saver_warning,
- Toast.LENGTH_LONG).show();
+ postWarningNotification();
+ } else {
+ cancelWarningNotification();
}
if (DEBUG) {
@@ -265,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/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/PinnedSliceState.java b/services/core/java/com/android/server/slice/PinnedSliceState.java
new file mode 100644
index 0000000..cf930f5
--- /dev/null
+++ b/services/core/java/com/android/server/slice/PinnedSliceState.java
@@ -0,0 +1,215 @@
+/*
+ * 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.ISliceListener;
+import android.app.slice.Slice;
+import android.app.slice.SliceProvider;
+import android.app.slice.SliceSpec;
+import android.content.ContentProviderClient;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.ArraySet;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Manages the state of a pinned slice.
+ */
+public class PinnedSliceState {
+
+ private static final long SLICE_TIMEOUT = 5000;
+ private static final String TAG = "PinnedSliceState";
+
+ private final Object mLock;
+
+ private final SliceManagerService mService;
+ private final Uri mUri;
+ @GuardedBy("mLock")
+ private final ArraySet<String> mPinnedPkgs = new ArraySet<>();
+ @GuardedBy("mLock")
+ private final ArraySet<ISliceListener> mListeners = new ArraySet<>();
+ @GuardedBy("mLock")
+ private SliceSpec[] mSupportedSpecs = null;
+
+ public PinnedSliceState(SliceManagerService service, Uri uri) {
+ mService = service;
+ mUri = uri;
+ mService.getHandler().post(this::handleSendPinned);
+ mLock = mService.getLock();
+ }
+
+ public SliceSpec[] getSpecs() {
+ return mSupportedSpecs;
+ }
+
+ public void mergeSpecs(SliceSpec[] supportedSpecs) {
+ synchronized (mLock) {
+ if (mSupportedSpecs == null) {
+ mSupportedSpecs = supportedSpecs;
+ } else {
+ List<SliceSpec> specs = Arrays.asList(mSupportedSpecs);
+ mSupportedSpecs = specs.stream().map(s -> {
+ SliceSpec other = findSpec(supportedSpecs, s.getType());
+ if (other == null) return null;
+ if (other.getRevision() < s.getRevision()) {
+ return other;
+ }
+ return s;
+ }).filter(s -> s != null).toArray(SliceSpec[]::new);
+ }
+ }
+ }
+
+ private SliceSpec findSpec(SliceSpec[] specs, String type) {
+ for (SliceSpec spec : specs) {
+ if (Objects.equals(spec.getType(), type)) {
+ return spec;
+ }
+ }
+ return null;
+ }
+
+ public Uri getUri() {
+ return mUri;
+ }
+
+ public void destroy() {
+ mService.getHandler().post(this::handleSendUnpinned);
+ }
+
+ public void onChange() {
+ mService.getHandler().post(this::handleBind);
+ }
+
+ public void addSliceListener(ISliceListener listener, SliceSpec[] specs) {
+ synchronized (mLock) {
+ if (mListeners.add(listener) && mListeners.size() == 1) {
+ mService.listen(mUri);
+ }
+ mergeSpecs(specs);
+ }
+ }
+
+ public boolean removeSliceListener(ISliceListener listener) {
+ synchronized (mLock) {
+ if (mListeners.remove(listener) && mListeners.size() == 0) {
+ mService.unlisten(mUri);
+ }
+ }
+ return !isPinned();
+ }
+
+ public void pin(String pkg, SliceSpec[] specs) {
+ synchronized (mLock) {
+ mPinnedPkgs.add(pkg);
+ mergeSpecs(specs);
+ }
+ }
+
+ public boolean unpin(String pkg) {
+ synchronized (mLock) {
+ mPinnedPkgs.remove(pkg);
+ }
+ return !isPinned();
+ }
+
+ public boolean isListening() {
+ synchronized (mLock) {
+ return !mListeners.isEmpty();
+ }
+ }
+
+ @VisibleForTesting
+ public boolean isPinned() {
+ synchronized (mLock) {
+ return !mPinnedPkgs.isEmpty() || !mListeners.isEmpty();
+ }
+ }
+
+ ContentProviderClient getClient() {
+ ContentProviderClient client =
+ mService.getContext().getContentResolver().acquireContentProviderClient(mUri);
+ client.setDetectNotResponding(SLICE_TIMEOUT);
+ return client;
+ }
+
+ private void handleBind() {
+ Slice s;
+ try (ContentProviderClient client = getClient()) {
+ Bundle extras = new Bundle();
+ extras.putParcelable(SliceProvider.EXTRA_BIND_URI, mUri);
+ extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
+ new ArrayList<>(Arrays.asList(mSupportedSpecs)));
+ final Bundle res;
+ try {
+ res = client.call(SliceProvider.METHOD_SLICE, null, extras);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to bind slice " + mUri, e);
+ return;
+ }
+ if (res == null) return;
+ Bundle.setDefusable(res, true);
+ s = res.getParcelable(SliceProvider.EXTRA_SLICE);
+ }
+ synchronized (mLock) {
+ mListeners.removeIf(l -> {
+ try {
+ l.onSliceUpdated(s);
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to notify slice " + mUri, e);
+ return true;
+ }
+ });
+ if (!isPinned()) {
+ // All the listeners died, remove from pinned state.
+ mService.removePinnedSlice(mUri);
+ }
+ }
+ }
+
+ private void handleSendPinned() {
+ try (ContentProviderClient client = getClient()) {
+ Bundle b = new Bundle();
+ b.putParcelable(SliceProvider.EXTRA_BIND_URI, mUri);
+ try {
+ client.call(SliceProvider.METHOD_PIN, null, b);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to contact " + mUri, e);
+ }
+ }
+ }
+
+ private void handleSendUnpinned() {
+ try (ContentProviderClient client = getClient()) {
+ Bundle b = new Bundle();
+ b.putParcelable(SliceProvider.EXTRA_BIND_URI, mUri);
+ try {
+ client.call(SliceProvider.METHOD_UNPIN, null, b);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to contact " + mUri, e);
+ }
+ }
+ }
+}
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..2d9e772
--- /dev/null
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -0,0 +1,352 @@
+/*
+ * 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 static android.content.ContentProvider.getUserIdFromUri;
+import static android.content.ContentProvider.maybeAddUserId;
+
+import android.Manifest.permission;
+import android.app.AppOpsManager;
+import android.app.slice.ISliceListener;
+import android.app.slice.ISliceManager;
+import android.app.slice.SliceSpec;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.AssistUtils;
+import com.android.internal.util.Preconditions;
+import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
+import com.android.server.SystemService;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class SliceManagerService extends ISliceManager.Stub {
+
+ private static final String TAG = "SliceManagerService";
+ private final Object mLock = new Object();
+
+ private final Context mContext;
+ private final PackageManagerInternal mPackageManagerInternal;
+ private final AppOpsManager mAppOps;
+ private final AssistUtils mAssistUtils;
+
+ @GuardedBy("mLock")
+ private final ArrayMap<Uri, PinnedSliceState> mPinnedSlicesByUri = new ArrayMap<>();
+ private final Handler mHandler;
+ private final ContentObserver mObserver;
+
+ public SliceManagerService(Context context) {
+ this(context, createHandler().getLooper());
+ }
+
+ @VisibleForTesting
+ SliceManagerService(Context context, Looper looper) {
+ mContext = context;
+ mPackageManagerInternal = Preconditions.checkNotNull(
+ LocalServices.getService(PackageManagerInternal.class));
+ mAppOps = context.getSystemService(AppOpsManager.class);
+ mAssistUtils = new AssistUtils(context);
+ mHandler = new Handler(looper);
+
+ mObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ try {
+ getPinnedSlice(uri).onChange();
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Received change for unpinned slice " + uri, e);
+ }
+ }
+ };
+ }
+
+ /// ----- Lifecycle stuff -----
+ private void systemReady() {
+ }
+
+ private void onUnlockUser(int userId) {
+ }
+
+ private void onStopUser(int userId) {
+ synchronized (mLock) {
+ mPinnedSlicesByUri.values().removeIf(s -> getUserIdFromUri(s.getUri()) == userId);
+ }
+ }
+
+ /// ----- ISliceManager stuff -----
+ @Override
+ public void addSliceListener(Uri uri, String pkg, ISliceListener listener, SliceSpec[] specs)
+ throws RemoteException {
+ verifyCaller(pkg);
+ uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
+ enforceAccess(pkg, uri);
+ getOrCreatePinnedSlice(uri).addSliceListener(listener, specs);
+ }
+
+ @Override
+ public void removeSliceListener(Uri uri, String pkg, ISliceListener listener)
+ throws RemoteException {
+ verifyCaller(pkg);
+ uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
+ enforceAccess(pkg, uri);
+ if (getPinnedSlice(uri).removeSliceListener(listener)) {
+ removePinnedSlice(uri);
+ }
+ }
+
+ @Override
+ public void pinSlice(String pkg, Uri uri, SliceSpec[] specs) throws RemoteException {
+ verifyCaller(pkg);
+ enforceFullAccess(pkg, "pinSlice", uri);
+ uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
+ getOrCreatePinnedSlice(uri).pin(pkg, specs);
+ }
+
+ @Override
+ public void unpinSlice(String pkg, Uri uri) throws RemoteException {
+ verifyCaller(pkg);
+ enforceFullAccess(pkg, "unpinSlice", uri);
+ uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
+ if (getPinnedSlice(uri).unpin(pkg)) {
+ removePinnedSlice(uri);
+ }
+ }
+
+ @Override
+ public boolean hasSliceAccess(String pkg) throws RemoteException {
+ verifyCaller(pkg);
+ return hasFullSliceAccess(pkg, Binder.getCallingUserHandle().getIdentifier());
+ }
+
+ @Override
+ public SliceSpec[] getPinnedSpecs(Uri uri, String pkg) throws RemoteException {
+ verifyCaller(pkg);
+ enforceAccess(pkg, uri);
+ return getPinnedSlice(uri).getSpecs();
+ }
+
+ /// ----- internal code -----
+ void removePinnedSlice(Uri uri) {
+ synchronized (mLock) {
+ mPinnedSlicesByUri.remove(uri).destroy();
+ }
+ }
+
+ private PinnedSliceState getPinnedSlice(Uri uri) {
+ synchronized (mLock) {
+ PinnedSliceState manager = mPinnedSlicesByUri.get(uri);
+ if (manager == null) {
+ throw new IllegalStateException(String.format("Slice %s not pinned",
+ uri.toString()));
+ }
+ return manager;
+ }
+ }
+
+ private PinnedSliceState getOrCreatePinnedSlice(Uri uri) {
+ synchronized (mLock) {
+ PinnedSliceState manager = mPinnedSlicesByUri.get(uri);
+ if (manager == null) {
+ manager = createPinnedSlice(uri);
+ mPinnedSlicesByUri.put(uri, manager);
+ }
+ return manager;
+ }
+ }
+
+ @VisibleForTesting
+ PinnedSliceState createPinnedSlice(Uri uri) {
+ return new PinnedSliceState(this, uri);
+ }
+
+ public Object getLock() {
+ return mLock;
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ public Handler getHandler() {
+ return mHandler;
+ }
+
+ private void enforceAccess(String pkg, Uri uri) {
+ getContext().enforceUriPermission(uri, permission.BIND_SLICE,
+ permission.BIND_SLICE, Binder.getCallingPid(), Binder.getCallingUid(),
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+ "Slice binding requires the permission BIND_SLICE");
+ int user = Binder.getCallingUserHandle().getIdentifier();
+ if (getUserIdFromUri(uri, user) != user) {
+ getContext().enforceCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL,
+ "Slice interaction across users requires INTERACT_ACROSS_USERS_FULL");
+ }
+ }
+
+ private void enforceFullAccess(String pkg, String name, Uri uri) {
+ int user = Binder.getCallingUserHandle().getIdentifier();
+ if (!hasFullSliceAccess(pkg, user)) {
+ throw new SecurityException(String.format("Call %s requires full slice access", name));
+ }
+ if (getUserIdFromUri(uri, user) != user) {
+ getContext().enforceCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL,
+ "Slice interaction across users requires INTERACT_ACROSS_USERS_FULL");
+ }
+ }
+
+ private void verifyCaller(String pkg) {
+ mAppOps.checkPackage(Binder.getCallingUid(), pkg);
+ }
+
+ private boolean hasFullSliceAccess(String pkg, int userId) {
+ return isDefaultHomeApp(pkg, userId) || isAssistant(pkg, userId)
+ || isGrantedFullAccess(pkg, userId);
+ }
+
+ private boolean isAssistant(String pkg, int userId) {
+ final ComponentName cn = mAssistUtils.getAssistComponentForUser(userId);
+ if (cn == null) {
+ return false;
+ }
+ return cn.getPackageName().equals(pkg);
+ }
+
+ public void listen(Uri uri) {
+ mContext.getContentResolver().registerContentObserver(uri, true, mObserver);
+ }
+
+ public void unlisten(Uri uri) {
+ mContext.getContentResolver().unregisterContentObserver(mObserver);
+ synchronized (mLock) {
+ mPinnedSlicesByUri.forEach((u, s) -> {
+ if (s.isListening()) {
+ listen(u);
+ }
+ });
+ }
+ }
+
+ private boolean isDefaultHomeApp(String pkg, int userId) {
+ String defaultHome = getDefaultHome(userId);
+ return Objects.equals(pkg, defaultHome);
+ }
+
+ // Based on getDefaultHome in ShortcutService.
+ // TODO: Unify if possible
+ @VisibleForTesting
+ String getDefaultHome(int userId) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
+
+ // Default launcher from package manager.
+ final ComponentName defaultLauncher = mPackageManagerInternal
+ .getHomeActivitiesAsUser(allHomeCandidates, userId);
+
+ ComponentName detected = null;
+ if (defaultLauncher != null) {
+ detected = defaultLauncher;
+ }
+
+ if (detected == null) {
+ // If we reach here, that means it's the first check since the user was created,
+ // and there's already multiple launchers and there's no default set.
+ // Find the system one with the highest priority.
+ // (We need to check the priority too because of FallbackHome in Settings.)
+ // If there's no system launcher yet, then no one can access slices, until
+ // the user explicitly sets one.
+ final int size = allHomeCandidates.size();
+
+ int lastPriority = Integer.MIN_VALUE;
+ for (int i = 0; i < size; i++) {
+ final ResolveInfo ri = allHomeCandidates.get(i);
+ if (!ri.activityInfo.applicationInfo.isSystemApp()) {
+ continue;
+ }
+ if (ri.priority < lastPriority) {
+ continue;
+ }
+ detected = ri.activityInfo.getComponentName();
+ lastPriority = ri.priority;
+ }
+ }
+ return detected.getPackageName();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private boolean isGrantedFullAccess(String pkg, int userId) {
+ // TODO: This will be user granted access, if we allow this through a prompt.
+ return false;
+ }
+
+ private static ServiceThread createHandler() {
+ ServiceThread handlerThread = new ServiceThread(TAG,
+ Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
+ handlerThread.start();
+ return handlerThread;
+ }
+
+ 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);
+ }
+
+ @Override
+ public void onStopUser(int userHandle) {
+ mService.onStopUser(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..251a277 100644
--- a/services/core/java/com/android/server/timezone/PackageStatusStorage.java
+++ b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
@@ -76,18 +76,22 @@
*/
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;
PackageStatusStorage(File storageDir) {
mPackageStatusFile = new AtomicFile(new File(storageDir, "package-status.xml"));
+ }
+
+ /**
+ * Initialize any storage, as needed.
+ *
+ * @throws IOException if the storage could not be initialized
+ */
+ void initialize() throws IOException {
if (!mPackageStatusFile.getBaseFile().exists()) {
- try {
- insertInitialPackageStatus();
- } catch (IOException e) {
- throw new IllegalStateException(e);
- }
+ insertInitialPackageStatus();
}
}
@@ -320,14 +324,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();
@@ -342,13 +346,13 @@
}
/** Only used during tests to force a known table state. */
- public void forceCheckStateForTests(int checkStatus, PackageVersions packageVersions) {
+ public void forceCheckStateForTests(int checkStatus, PackageVersions packageVersions)
+ throws IOException {
synchronized (this) {
try {
- int optimisticLockId = getCurrentOptimisticLockId();
- writePackageStatusWithOptimisticLockCheck(optimisticLockId, optimisticLockId,
- checkStatus, packageVersions);
- } catch (IOException | ParseException e) {
+ final int initialOptimisticLockId = (int) System.currentTimeMillis();
+ writePackageStatusLocked(checkStatus, initialOptimisticLockId, packageVersions);
+ } catch (IOException e) {
throw new IllegalStateException(e);
}
}
diff --git a/services/core/java/com/android/server/timezone/PackageTracker.java b/services/core/java/com/android/server/timezone/PackageTracker.java
index f0306b9..0e8d8bc 100644
--- a/services/core/java/com/android/server/timezone/PackageTracker.java
+++ b/services/core/java/com/android/server/timezone/PackageTracker.java
@@ -22,11 +22,15 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Environment;
+import android.os.FileUtils;
+import android.os.SystemClock;
import android.provider.TimeZoneRulesDataContract;
import android.util.Slog;
import java.io.File;
+import java.io.IOException;
import java.io.PrintWriter;
+import java.time.Clock;
/**
* Monitors the installed applications associated with time zone updates. If the app packages are
@@ -58,7 +62,7 @@
private final IntentHelper mIntentHelper;
private final ConfigHelper mConfigHelper;
private final PackageStatusStorage mPackageStatusStorage;
- private final ClockHelper mClockHelper;
+ private final Clock mElapsedRealtimeClock;
// False if tracking is disabled.
private boolean mTrackingEnabled;
@@ -91,15 +95,11 @@
/** Creates the {@link PackageTracker} for normal use. */
static PackageTracker create(Context context) {
+ Clock elapsedRealtimeClock = SystemClock.elapsedRealtimeClock();
PackageTrackerHelperImpl helperImpl = new PackageTrackerHelperImpl(context);
- // TODO(nfuller): Switch to FileUtils.createDir() when available. http://b/31008728
- File storageDir = new File(Environment.getDataSystemDirectory(), "timezone");
- if (!storageDir.exists()) {
- storageDir.mkdir();
- }
-
+ File storageDir = FileUtils.createDir(Environment.getDataSystemDirectory(), "timezone");
return new PackageTracker(
- helperImpl /* clock */,
+ elapsedRealtimeClock /* elapsedRealtimeClock */,
helperImpl /* configHelper */,
helperImpl /* packageManagerHelper */,
new PackageStatusStorage(storageDir),
@@ -107,10 +107,10 @@
}
// A constructor that can be used by tests to supply mocked / faked dependencies.
- PackageTracker(ClockHelper clockHelper, ConfigHelper configHelper,
+ PackageTracker(Clock elapsedRealtimeClock, ConfigHelper configHelper,
PackageManagerHelper packageManagerHelper, PackageStatusStorage packageStatusStorage,
IntentHelper intentHelper) {
- mClockHelper = clockHelper;
+ mElapsedRealtimeClock = elapsedRealtimeClock;
mConfigHelper = configHelper;
mPackageManagerHelper = packageManagerHelper;
mPackageStatusStorage = packageStatusStorage;
@@ -118,11 +118,11 @@
}
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- protected synchronized void start() {
+ protected synchronized boolean start() {
mTrackingEnabled = mConfigHelper.isTrackingEnabled();
if (!mTrackingEnabled) {
Slog.i(TAG, "Time zone updater / data package tracking explicitly disabled.");
- return;
+ return false;
}
mUpdateAppPackageName = mConfigHelper.getUpdateAppPackageName();
@@ -140,6 +140,14 @@
mCheckTriggered = false;
mCheckFailureCount = 0;
+ // Initialize the storage, as needed.
+ try {
+ mPackageStatusStorage.initialize();
+ } catch (IOException e) {
+ Slog.w(TAG, "PackageTracker storage could not be initialized.", e);
+ return false;
+ }
+
// Initialize the intent helper.
mIntentHelper.initialize(mUpdateAppPackageName, mDataAppPackageName, this);
@@ -149,6 +157,7 @@
mIntentHelper.scheduleReliabilityTrigger(mDelayBeforeReliabilityCheckMillis);
Slog.i(TAG, "Time zone updater / data package tracking enabled");
+ return true;
}
/**
@@ -425,7 +434,7 @@
}
private void setCheckInProgress() {
- mLastTriggerTimestamp = mClockHelper.currentTimestamp();
+ mLastTriggerTimestamp = mElapsedRealtimeClock.millis();
}
private void setCheckComplete() {
@@ -441,12 +450,12 @@
return false;
}
// Risk of overflow, but highly unlikely given the implementation and not problematic.
- return mClockHelper.currentTimestamp() > mLastTriggerTimestamp + mCheckTimeAllowedMillis;
+ return mElapsedRealtimeClock.millis() > mLastTriggerTimestamp + mCheckTimeAllowedMillis;
}
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..5f90be1 100644
--- a/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
@@ -25,7 +25,6 @@
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Slog;
@@ -34,7 +33,7 @@
/**
* A single class that implements multiple helper interfaces for use by {@link PackageTracker}.
*/
-final class PackageTrackerHelperImpl implements ClockHelper, ConfigHelper, PackageManagerHelper {
+final class PackageTrackerHelperImpl implements ConfigHelper, PackageManagerHelper {
private static final String TAG = "PackageTrackerHelperImpl";
@@ -74,18 +73,11 @@
}
@Override
- public long currentTimestamp() {
- // Use of elapsedRealtime() because this is in-memory state and elapsedRealtime() shouldn't
- // change if the system clock changes.
- return SystemClock.elapsedRealtime();
- }
-
- @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/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
index 52b49ba..30fc63c 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -121,6 +121,7 @@
}
public void start() {
+ // Return value deliberately ignored: no action required on failure to start.
mPackageTracker.start();
}
diff --git a/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java b/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
index 0cf61c0..e8a401e 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
@@ -16,6 +16,8 @@
package com.android.server.timezone;
+import com.android.internal.util.DumpUtils;
+
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
@@ -46,15 +48,7 @@
@Override
public boolean checkDumpPermission(String tag, PrintWriter pw) {
- // TODO(nfuller): Switch to DumpUtils.checkDumpPermission() when it is available in AOSP.
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump LocationManagerService from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return false;
- }
- return true;
+ return DumpUtils.checkDumpPermission(mContext, tag, pw);
}
@Override
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/wallpaper/IWallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/IWallpaperManagerService.java
new file mode 100644
index 0000000..60b08dd
--- /dev/null
+++ b/services/core/java/com/android/server/wallpaper/IWallpaperManagerService.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 com.android.server.wallpaper;
+
+import android.app.IWallpaperManager;
+import android.os.IBinder;
+
+/**
+ * Extended IWallpaperManager which can receive SystemService's lifetime events.
+ */
+interface IWallpaperManagerService extends IWallpaperManager, IBinder {
+ /**
+ * @see com.android.server.SystemService#onBootPhase(int)
+ */
+ void onBootPhase(int phase);
+
+ /**
+ * @see com.android.server.SystemService#onUnlockUser(int)
+ */
+ void onUnlockUser(final int userId);
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index b888ec2..7b0ed0d 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -99,6 +99,7 @@
import com.android.server.FgThread;
import com.android.server.SystemService;
+import java.lang.reflect.InvocationTargetException;
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -119,14 +120,16 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import com.android.internal.R;
-public class WallpaperManagerService extends IWallpaperManager.Stub {
+public class WallpaperManagerService extends IWallpaperManager.Stub
+ implements IWallpaperManagerService {
static final String TAG = "WallpaperManagerService";
static final boolean DEBUG = false;
static final boolean DEBUG_LIVE = DEBUG || true;
public static class Lifecycle extends SystemService {
- private WallpaperManagerService mService;
+ private IWallpaperManagerService mService;
public Lifecycle(Context context) {
super(context);
@@ -134,22 +137,30 @@
@Override
public void onStart() {
- mService = new WallpaperManagerService(getContext());
- publishBinderService(Context.WALLPAPER_SERVICE, mService);
+ try {
+ final Class<? extends IWallpaperManagerService> klass =
+ (Class<? extends IWallpaperManagerService>)Class.forName(
+ getContext().getResources().getString(
+ R.string.config_wallpaperManagerServiceName));
+ mService = klass.getConstructor(Context.class).newInstance(getContext());
+ publishBinderService(Context.WALLPAPER_SERVICE, mService);
+ } catch (Exception exp) {
+ Slog.wtf(TAG, "Failed to instantiate WallpaperManagerService", exp);
+ }
}
@Override
public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
- mService.systemReady();
- } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
- mService.switchUser(UserHandle.USER_SYSTEM, null);
+ if (mService != null) {
+ mService.onBootPhase(phase);
}
}
@Override
public void onUnlockUser(int userHandle) {
- mService.onUnlockUser(userHandle);
+ if (mService != null) {
+ mService.onUnlockUser(userHandle);
+ }
}
}
@@ -1255,7 +1266,17 @@
mLockWallpaperMap.remove(userId);
}
- void onUnlockUser(final int userId) {
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ systemReady();
+ } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+ switchUser(UserHandle.USER_SYSTEM, null);
+ }
+ }
+
+ @Override
+ public void onUnlockUser(final int userId) {
synchronized (mLock) {
if (mCurrentUserId == userId) {
if (mWaitingForUnlock) {
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/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java
new file mode 100644
index 0000000..84d47b4
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AnimationAdapter.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.server.wm;
+
+import android.annotation.ColorInt;
+import android.graphics.Point;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+import android.view.animation.Animation;
+
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+
+/**
+ * Interface that describes an animation and bridges the animation start to the component
+ * responsible for running the animation.
+ */
+interface AnimationAdapter {
+
+ /**
+ * @return Whether we should detach the wallpaper during the animation.
+ * @see Animation#setDetachWallpaper
+ */
+ boolean getDetachWallpaper();
+
+ /**
+ * @return The background color behind the animation.
+ */
+ @ColorInt int getBackgroundColor();
+
+ /**
+ * Requests to start the animation.
+ *
+ * @param animationLeash The surface to run the animation on. See {@link SurfaceAnimator} for an
+ * overview of the mechanism. This surface needs to be released by the
+ * component running the animation after {@code finishCallback} has been
+ * invoked, or after the animation was cancelled.
+ * @param t The Transaction to apply the initial frame of the animation.
+ * @param finishCallback The callback to be invoked when the animation has finished.
+ */
+ void startAnimation(SurfaceControl animationLeash, Transaction t,
+ OnAnimationFinishedCallback finishCallback);
+
+ /**
+ * Called when the animation that was started with {@link #startAnimation} was cancelled by the
+ * window manager.
+ *
+ * @param animationLeash The leash passed to {@link #startAnimation}.
+ */
+ void onAnimationCancelled(SurfaceControl animationLeash);
+
+ /**
+ * @return The approximate duration of the animation, in milliseconds.
+ */
+ long getDurationHint();
+}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index c39ce98..94a0cb7 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -66,6 +66,7 @@
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
+import android.view.animation.Transformation;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.input.InputApplicationHandle;
@@ -75,6 +76,7 @@
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.LinkedList;
class AppTokenList extends ArrayList<AppWindowToken> {
}
@@ -231,7 +233,7 @@
// If this initial window is animating, stop it -- we will do an animation to reveal
// it from behind the starting window, so there is no need for it to also be doing its
// own stuff.
- winAnimator.clearAnimation();
+ win.cancelAnimation();
if (getController() != null) {
getController().removeStartingWindow();
}
@@ -389,7 +391,7 @@
}
for (int i = mChildren.size() - 1; i >= 0 && !delayed; i--) {
- if ((mChildren.get(i)).isWindowAnimationSet()) {
+ if ((mChildren.get(i)).isSelfOrChildAnimating()) {
delayed = true;
}
}
@@ -610,8 +612,12 @@
*/
private void destroySurfaces(boolean cleanupOnResume) {
boolean destroyedSomething = false;
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState win = mChildren.get(i);
+
+ // Copying to a different list as multiple children can be removed.
+ // TODO: Not sure why this is needed.
+ final LinkedList<WindowState> children = new LinkedList<>(mChildren);
+ for (int i = children.size() - 1; i >= 0; i--) {
+ final WindowState win = children.get(i);
destroyedSomething |= win.destroySurface(cleanupOnResume, mAppStopped);
}
if (destroyedSomething) {
@@ -1320,7 +1326,7 @@
+ " pv=" + w.mPolicyVisibility
+ " mDrawState=" + winAnimator.drawStateToString()
+ " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested
- + " a=" + winAnimator.mAnimating);
+ + " a=" + winAnimator.isAnimationSet());
}
}
@@ -1520,6 +1526,11 @@
}
@Override
+ boolean isSelfAnimating() {
+ return mAppAnimator.isAnimating();
+ }
+
+ @Override
void dump(PrintWriter pw, String prefix) {
super.dump(pw, prefix);
if (appToken != null) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 41348ba..f458457 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;
@@ -145,6 +146,7 @@
import android.view.MagnificationSpec;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
import com.android.internal.annotations.VisibleForTesting;
@@ -178,20 +180,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 AboveAppWindowContainers mAboveAppWindowsContainers =
- new 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 +319,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;
@@ -340,6 +340,7 @@
new ApplySurfaceChangesTransactionState();
private final ScreenshotApplicationState mScreenshotApplicationState =
new ScreenshotApplicationState();
+ private final Transaction mTmpTransaction = new Transaction();
// True if this display is in the process of being removed. Used to determine if the removal of
// the display's direct children should be allowed.
@@ -380,29 +381,11 @@
*/
private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
+ /** Temporary float array to retrieve 3x3 matrix values. */
+ private final float[] mTmpFloats = new float[9];
+
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
- if (winAnimator.hasSurface()) {
- final boolean wasAnimating = winAnimator.mWasAnimating;
- final boolean nowAnimating = winAnimator.stepAnimationLocked(
- mTmpWindowAnimator.mCurrentTime);
- winAnimator.mWasAnimating = nowAnimating;
- mTmpWindowAnimator.orAnimating(nowAnimating);
-
- if (DEBUG_WALLPAPER) Slog.v(TAG,
- w + ": wasAnimating=" + wasAnimating + ", nowAnimating=" + nowAnimating);
-
- if (wasAnimating && !winAnimator.mAnimating
- && mWallpaperController.isWallpaperTarget(w)) {
- mTmpWindowAnimator.mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
- pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- if (DEBUG_LAYOUT_REPEATS) {
- mService.mWindowPlacerLocked.debugLayoutRepeats(
- "updateWindowsAndWallpaperLocked 2", pendingLayoutChanges);
- }
- }
- }
-
final AppWindowToken atoken = w.mAppToken;
if (winAnimator.mDrawState == READY_TO_SHOW) {
if (atoken == null || atoken.allDrawn) {
@@ -435,13 +418,13 @@
// If this window is animating, make a note that we have an animating window and take
// care of a request to run a detached wallpaper animation.
- if (winAnimator.mAnimating) {
- if (winAnimator.mAnimation != null) {
- if ((flags & FLAG_SHOW_WALLPAPER) != 0
- && winAnimator.mAnimation.getDetachWallpaper()) {
+ if (winAnimator.isAnimationSet()) {
+ final AnimationAdapter anim = w.getAnimation();
+ if (anim != null) {
+ if ((flags & FLAG_SHOW_WALLPAPER) != 0 && anim.getDetachWallpaper()) {
mTmpWindow = w;
}
- final int color = winAnimator.mAnimation.getBackgroundColor();
+ final int color = anim.getBackgroundColor();
if (color != 0) {
final TaskStack stack = w.getStack();
if (stack != null) {
@@ -449,7 +432,6 @@
}
}
}
- mTmpWindowAnimator.setAnimating(true);
}
// If this window's app token is running a detached wallpaper animation, make a note so
@@ -685,7 +667,10 @@
mWallpaperController.updateWallpaperVisibility();
}
- w.handleWindowMovedIfNeeded();
+ // Use mTmpTransaction instead of mPendingTransaction because we don't want to commit
+ // other changes in mPendingTransaction at this point.
+ w.handleWindowMovedIfNeeded(mTmpTransaction);
+ SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
final WindowStateAnimator winAnimator = w.mWinAnimator;
@@ -721,7 +706,7 @@
}
}
final TaskStack stack = w.getStack();
- if ((!winAnimator.isAnimationStarting() && !winAnimator.isWaitingForOpening())
+ if ((!winAnimator.isWaitingForOpening())
|| (stack != null && stack.isAnimatingBounds())) {
// Updates the shown frame before we set up the surface. This is needed
// because the resizing could change the top-left position (in addition to
@@ -737,6 +722,12 @@
winAnimator.computeShownFrameLocked();
}
winAnimator.setSurfaceBoundariesLocked(mTmpRecoveringMemory /* recoveringMemory */);
+
+ // Since setSurfaceBoundariesLocked applies the clipping, we need to apply the position
+ // to the surface of the window container as well. Use mTmpTransaction instead of
+ // mPendingTransaction to avoid committing any existing changes in there.
+ w.updateSurfacePosition(mTmpTransaction);
+ SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
}
final AppWindowToken atoken = w.mAppToken;
@@ -765,6 +756,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())
@@ -777,7 +769,6 @@
display.getDisplayInfo(mDisplayInfo);
display.getMetrics(mDisplayMetrics);
isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
- mService = service;
mDisplayFrames = new DisplayFrames(mDisplayId, mDisplayInfo);
initializeDisplayBaseInfo();
mDividerControllerLocked = new DockedStackDividerController(service, this);
@@ -1767,8 +1758,8 @@
updateBounds();
}
- void getContentRect(Rect out) {
- out.set(mDisplayFrames.mContent);
+ void getStableRect(Rect out) {
+ out.set(mDisplayFrames.mStable);
}
TaskStack createStack(int stackId, boolean onTop, StackWindowController controller) {
@@ -2339,6 +2330,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();
@@ -2349,6 +2341,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
@@ -2616,8 +2609,7 @@
forAllWindows(w -> {
if (w.mAppToken == null && policy.canBeHiddenByKeyguardLw(w)
&& w.wouldBeVisibleIfPolicyIgnored() && !w.isVisible()) {
- w.mWinAnimator.setAnimation(
- policy.createHiddenByKeyguardExit(onWallpaper, goingToShade));
+ w.startAnimation(policy.createHiddenByKeyguardExit(onWallpaper, goingToShade));
}
}, true /* traverseTopToBottom */);
}
@@ -3182,6 +3174,10 @@
*/
static class DisplayChildWindowContainer<E extends WindowContainer> extends WindowContainer<E> {
+ DisplayChildWindowContainer(WindowManagerService service) {
+ super(service);
+ }
+
@Override
boolean fillsParent() {
return true;
@@ -3209,6 +3205,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.
@@ -3516,35 +3516,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
@@ -3560,8 +3562,8 @@
}
private final class AboveAppWindowContainers extends NonAppWindowContainers {
- AboveAppWindowContainers(String name) {
- super(name);
+ AboveAppWindowContainers(String name, WindowManagerService service) {
+ super(name, service);
}
void assignChildLayers(SurfaceControl.Transaction t, WindowContainer imeContainer) {
@@ -3574,15 +3576,15 @@
int layer = mService.mPolicy.getWindowLayerFromTypeLw(
wt.windowType, wt.mOwnerCanManageAppTokens);
- if (needAssignIme && layer >= TYPE_INPUT_METHOD_DIALOG) {
- t.setRelativeLayer(imeContainer.getSurfaceControl(),
- wt.getSurfaceControl(), -1);
+
+ if (needAssignIme && layer >= mService.mPolicy.getWindowLayerFromTypeLw(
+ TYPE_INPUT_METHOD_DIALOG, true)) {
+ imeContainer.assignRelativeLayer(t, wt.getSurfaceControl(), -1);
needAssignIme = false;
}
}
if (needAssignIme) {
- t.setRelativeLayer(imeContainer.getSurfaceControl(),
- getSurfaceControl(), Integer.MIN_VALUE);
+ imeContainer.assignRelativeLayer(t, getSurfaceControl(), Integer.MAX_VALUE);
}
}
}
@@ -3616,7 +3618,8 @@
};
private final String mName;
- NonAppWindowContainers(String name) {
+ NonAppWindowContainers(String name, WindowManagerService service) {
+ super(service);
mName = name;
}
@@ -3710,8 +3713,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);
@@ -3735,8 +3736,7 @@
// place it in the AboveAppWindowContainers.
if (imeTarget != null && !imeTarget.inSplitScreenWindowingMode()
&& (imeTarget.getSurfaceControl() != null)) {
- t.setRelativeLayer(mImeWindowsContainers.getSurfaceControl(),
- imeTarget.getSurfaceControl(),
+ 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);
@@ -3766,13 +3766,13 @@
}
@Override
- void destroyAfterPendingTransaction(SurfaceControl surface) {
+ public void destroyAfterPendingTransaction(SurfaceControl surface) {
mPendingDestroyingSurfaces.add(surface);
}
/**
* Destroys any surfaces that have been put into the pending list with
- * {@link #destroyAfterTransaction}.
+ * {@link #destroyAfterPendingTransaction}.
*/
void onPendingTransactionApplied() {
for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
@@ -3780,4 +3780,21 @@
}
mPendingDestroyingSurfaces.clear();
}
+
+ @Override
+ void prepareSurfaces() {
+ final ScreenRotationAnimation screenRotationAnimation =
+ mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
+ if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
+ screenRotationAnimation.getEnterTransformation().getMatrix().getValues(mTmpFloats);
+ mPendingTransaction.setMatrix(mWindowingLayer,
+ mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
+ mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
+ mPendingTransaction.setPosition(mWindowingLayer,
+ mTmpFloats[Matrix.MTRANS_X], mTmpFloats[Matrix.MTRANS_Y]);
+ mPendingTransaction.setAlpha(mWindowingLayer,
+ screenRotationAnimation.getEnterTransformation().getAlpha());
+ }
+ super.prepareSurfaces();
+ }
}
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/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index a37598e..03c0768 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -751,10 +751,10 @@
// There might be an old window delaying the animation start - clear it.
if (mDelayedImeWin != null) {
- mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
+ mDelayedImeWin.endDelayingAnimationStart();
}
mDelayedImeWin = imeWin;
- imeWin.mWinAnimator.startDelayingAnimationStart();
+ imeWin.startDelayingAnimationStart();
}
// If we are already waiting for something to be drawn, clear out the old one so it
@@ -765,25 +765,27 @@
mService.mWaitingForDrawnCallback.run();
}
mService.mWaitingForDrawnCallback = () -> {
- mAnimationStartDelayed = false;
- if (mDelayedImeWin != null) {
- mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
+ synchronized (mService.mWindowMap) {
+ mAnimationStartDelayed = false;
+ if (mDelayedImeWin != null) {
+ mDelayedImeWin.endDelayingAnimationStart();
+ }
+ // If the adjust status changed since this was posted, only notify
+ // the new states and don't animate.
+ long duration = 0;
+ if (mAdjustedForIme == adjustedForIme
+ && mAdjustedForDivider == adjustedForDivider) {
+ duration = IME_ADJUST_ANIM_DURATION;
+ } else {
+ Slog.w(TAG, "IME adjust changed while waiting for drawn:"
+ + " adjustedForIme=" + adjustedForIme
+ + " adjustedForDivider=" + adjustedForDivider
+ + " mAdjustedForIme=" + mAdjustedForIme
+ + " mAdjustedForDivider=" + mAdjustedForDivider);
+ }
+ notifyAdjustedForImeChanged(
+ mAdjustedForIme || mAdjustedForDivider, duration);
}
- // If the adjust status changed since this was posted, only notify
- // the new states and don't animate.
- long duration = 0;
- if (mAdjustedForIme == adjustedForIme
- && mAdjustedForDivider == adjustedForDivider) {
- duration = IME_ADJUST_ANIM_DURATION;
- } else {
- Slog.w(TAG, "IME adjust changed while waiting for drawn:"
- + " adjustedForIme=" + adjustedForIme
- + " adjustedForDivider=" + adjustedForDivider
- + " mAdjustedForIme=" + mAdjustedForIme
- + " mAdjustedForDivider=" + mAdjustedForDivider);
- }
- notifyAdjustedForImeChanged(
- mAdjustedForIme || mAdjustedForDivider, duration);
};
} else {
notifyAdjustedForImeChanged(
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 65951dc..28b4c1d 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -40,6 +40,7 @@
import com.android.internal.util.Preconditions;
import com.android.server.input.InputWindowHandle;
import com.android.server.wm.WindowManagerInternal.IDragDropCallback;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Managing drag and drop operations initiated by View#startDragAndDrop.
@@ -67,42 +68,10 @@
private final Handler mHandler;
/**
- * Lock to preserve the order of state updates.
- * The lock is used to process drag and drop state updates in order without having the window
- * manager lock.
- *
- * Suppose DragDropController invokes a callback method A, then processes the following update
- * A'. Same for a callback method B and the following update B'. The callback wants
- * DragDropController to processes the updates in the order of A' then B'.
- *
- * Without mWriteLock: the following race can happen.
- *
- * 1. Thread a calls A.
- * 2. Thread b calls B.
- * 3. Thread b acquires the window manager lock
- * 4. thread b processes the update B'
- * 5. Thread a acquires the window manager lock
- * 6. thread a processes the update A'
- *
- * With mWriteLock we can ensure the order of A' and B'
- *
- * 1. Thread a acquire mWriteLock
- * 2. Thread a calls A
- * 3. Thread a acquire the window manager lock
- * 4. Thread a processes A'
- * 5. Thread b acquire mWriteLock
- * 6. Thread b calls B
- * 7. Thread b acquire the window manager lock
- * 8. Thread b processes B'
- *
- * Don't acquire the lock while holding the window manager lock, otherwise it causes a deadlock.
- */
- private final Object mWriteLock = new Object();
-
- /**
* Callback which is used to sync drag state with the vendor-specific code.
*/
- @NonNull private IDragDropCallback mCallback = new IDragDropCallback() {};
+ @NonNull private AtomicReference<IDragDropCallback> mCallback = new AtomicReference<>(
+ new IDragDropCallback() {});
boolean dragDropActiveLocked() {
return mDragState != null;
@@ -114,9 +83,7 @@
void registerCallback(IDragDropCallback callback) {
Preconditions.checkNotNull(callback);
- synchronized (mWriteLock) {
- mCallback = callback;
- }
+ mCallback.set(callback);
}
DragDropController(WindowManagerService service, Looper looper) {
@@ -136,45 +103,48 @@
+ " asbinder=" + window.asBinder());
}
- synchronized (mWriteLock) {
- synchronized (mService.mWindowMap) {
- if (dragDropActiveLocked()) {
- Slog.w(TAG_WM, "Drag already in progress");
- return null;
- }
+ if (width <= 0 || height <= 0) {
+ Slog.w(TAG_WM, "width and height of drag shadow must be positive");
+ return null;
+ }
- // TODO(multi-display): support other displays
- final DisplayContent displayContent =
- mService.getDefaultDisplayContentLocked();
- final Display display = displayContent.getDisplay();
-
- final SurfaceControl surface = new SurfaceControl.Builder(session)
- .setName("drag surface")
- .setSize(width, height)
- .setFormat(PixelFormat.TRANSLUCENT)
- .build();
- surface.setLayerStack(display.getLayerStack());
- float alpha = 1;
- if ((flags & View.DRAG_FLAG_OPAQUE) == 0) {
- alpha = DRAG_SHADOW_ALPHA_TRANSPARENT;
- }
- surface.setAlpha(alpha);
-
- if (SHOW_TRANSACTIONS)
- Slog.i(TAG_WM, " DRAG " + surface + ": CREATE");
- outSurface.copyFrom(surface);
- final IBinder winBinder = window.asBinder();
- IBinder token = new Binder();
- mDragState = new DragState(mService, token, surface, flags, winBinder);
- mDragState.mPid = callerPid;
- mDragState.mUid = callerUid;
- mDragState.mOriginalAlpha = alpha;
- token = mDragState.mToken = new Binder();
-
- // 5 second timeout for this window to actually begin the drag
- sendTimeoutMessage(MSG_DRAG_START_TIMEOUT, winBinder);
- return token;
+ synchronized (mService.mWindowMap) {
+ if (dragDropActiveLocked()) {
+ Slog.w(TAG_WM, "Drag already in progress");
+ return null;
}
+
+ // TODO(multi-display): support other displays
+ final DisplayContent displayContent =
+ mService.getDefaultDisplayContentLocked();
+ final Display display = displayContent.getDisplay();
+
+ final SurfaceControl surface = new SurfaceControl.Builder(session)
+ .setName("drag surface")
+ .setSize(width, height)
+ .setFormat(PixelFormat.TRANSLUCENT)
+ .build();
+ surface.setLayerStack(display.getLayerStack());
+ float alpha = 1;
+ if ((flags & View.DRAG_FLAG_OPAQUE) == 0) {
+ alpha = DRAG_SHADOW_ALPHA_TRANSPARENT;
+ }
+ surface.setAlpha(alpha);
+
+ if (SHOW_TRANSACTIONS)
+ Slog.i(TAG_WM, " DRAG " + surface + ": CREATE");
+ outSurface.copyFrom(surface);
+ final IBinder winBinder = window.asBinder();
+ IBinder token = new Binder();
+ mDragState = new DragState(mService, token, surface, flags, winBinder);
+ mDragState.mPid = callerPid;
+ mDragState.mUid = callerUid;
+ mDragState.mOriginalAlpha = alpha;
+ token = mDragState.mToken = new Binder();
+
+ // 5 second timeout for this window to actually begin the drag
+ sendTimeoutMessage(MSG_DRAG_START_TIMEOUT, winBinder);
+ return token;
}
}
@@ -185,84 +155,89 @@
Slog.d(TAG_WM, "perform drag: win=" + window + " data=" + data);
}
- synchronized (mWriteLock) {
- if (!mCallback.performDrag(window, dragToken, touchSource, touchX, touchY, thumbCenterX,
- thumbCenterY, data)) {
- return false;
- }
+ final boolean callbackResult = mCallback.get().prePerformDrag(window, dragToken,
+ touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data);
+ try {
synchronized (mService.mWindowMap) {
- if (mDragState == null) {
- Slog.w(TAG_WM, "No drag prepared");
- throw new IllegalStateException("performDrag() without prepareDrag()");
- }
-
- if (dragToken != mDragState.mToken) {
- Slog.w(TAG_WM, "Performing mismatched drag");
- throw new IllegalStateException("performDrag() does not match prepareDrag()");
- }
-
- final WindowState callingWin = mService.windowForClientLocked(null, window, false);
- if (callingWin == null) {
- Slog.w(TAG_WM, "Bad requesting window " + window);
- return false; // !!! TODO: throw here?
- }
-
- // !!! TODO: if input is not still focused on the initiating window, fail
- // the drag initiation (e.g. an alarm window popped up just as the application
- // called performDrag()
-
mHandler.removeMessages(MSG_DRAG_START_TIMEOUT, window.asBinder());
-
- // !!! TODO: extract the current touch (x, y) in screen coordinates. That
- // will let us eliminate the (touchX,touchY) parameters from the API.
-
- // !!! FIXME: put all this heavy stuff onto the mHandler looper, as well as
- // the actual drag event dispatch stuff in the dragstate
-
- final DisplayContent displayContent = callingWin.getDisplayContent();
- if (displayContent == null) {
- return false;
- }
- Display display = displayContent.getDisplay();
- mDragState.register(display);
- if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel,
- mDragState.getInputChannel())) {
- Slog.e(TAG_WM, "Unable to transfer touch focus");
- mDragState.closeLocked();
- return false;
- }
-
- mDragState.mDisplayContent = displayContent;
- mDragState.mData = data;
- mDragState.broadcastDragStartedLocked(touchX, touchY);
- mDragState.overridePointerIconLocked(touchSource);
-
- // remember the thumb offsets for later
- mDragState.mThumbOffsetX = thumbCenterX;
- mDragState.mThumbOffsetY = thumbCenterY;
-
- // Make the surface visible at the proper location
- final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag");
- mService.openSurfaceTransaction();
try {
- surfaceControl.setPosition(touchX - thumbCenterX,
- touchY - thumbCenterY);
- surfaceControl.setLayer(mDragState.getDragLayerLocked());
- surfaceControl.setLayerStack(display.getLayerStack());
- surfaceControl.show();
+ if (!callbackResult) {
+ return false;
+ }
+
+ Preconditions.checkState(
+ mDragState != null, "performDrag() without prepareDrag()");
+ Preconditions.checkState(
+ mDragState.mToken == dragToken,
+ "performDrag() does not match prepareDrag()");
+
+ final WindowState callingWin = mService.windowForClientLocked(
+ null, window, false);
+ if (callingWin == null) {
+ Slog.w(TAG_WM, "Bad requesting window " + window);
+ return false; // !!! TODO: throw here?
+ }
+
+ // !!! TODO: if input is not still focused on the initiating window, fail
+ // the drag initiation (e.g. an alarm window popped up just as the application
+ // called performDrag()
+
+ // !!! TODO: extract the current touch (x, y) in screen coordinates. That
+ // will let us eliminate the (touchX,touchY) parameters from the API.
+
+ // !!! FIXME: put all this heavy stuff onto the mHandler looper, as well as
+ // the actual drag event dispatch stuff in the dragstate
+
+ final DisplayContent displayContent = callingWin.getDisplayContent();
+ if (displayContent == null) {
+ Slog.w(TAG_WM, "display content is null");
+ return false;
+ }
+
+ final Display display = displayContent.getDisplay();
+ mDragState.register(display);
+ if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel,
+ mDragState.getInputChannel())) {
+ Slog.e(TAG_WM, "Unable to transfer touch focus");
+ return false;
+ }
+
+ mDragState.mDisplayContent = displayContent;
+ mDragState.mData = data;
+ mDragState.broadcastDragStartedLocked(touchX, touchY);
+ mDragState.overridePointerIconLocked(touchSource);
+ // remember the thumb offsets for later
+ mDragState.mThumbOffsetX = thumbCenterX;
+ mDragState.mThumbOffsetY = thumbCenterY;
+
+ // Make the surface visible at the proper location
+ final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag");
+ mService.openSurfaceTransaction();
+ try {
+ surfaceControl.setPosition(touchX - thumbCenterX,
+ touchY - thumbCenterY);
+ surfaceControl.setLayer(mDragState.getDragLayerLocked());
+ surfaceControl.setLayerStack(display.getLayerStack());
+ surfaceControl.show();
+ } finally {
+ mService.closeSurfaceTransaction("performDrag");
+ if (SHOW_LIGHT_TRANSACTIONS) {
+ Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
+ }
+ }
+
+ mDragState.notifyLocationLocked(touchX, touchY);
} finally {
- mService.closeSurfaceTransaction("performDrag");
- if (SHOW_LIGHT_TRANSACTIONS) {
- Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
+ if (mDragState != null && !mDragState.isInProgress()) {
+ mDragState.closeLocked();
}
}
-
- mDragState.notifyLocationLocked(touchX, touchY);
}
+ return true; // success!
+ } finally {
+ mCallback.get().postPerformDrag();
}
-
- return true; // success!
}
void reportDropResult(IWindow window, boolean consumed) {
@@ -271,8 +246,8 @@
Slog.d(TAG_WM, "Drop result=" + consumed + " reported by " + token);
}
- synchronized (mWriteLock) {
- mCallback.reportDropResult(window, consumed);
+ mCallback.get().preReportDropResult(window, consumed);
+ try {
synchronized (mService.mWindowMap) {
if (mDragState == null) {
// Most likely the drop recipient ANRed and we ended the drag
@@ -297,10 +272,11 @@
return; // !!! TODO: throw here?
}
-
mDragState.mDragResult = consumed;
mDragState.endDragLocked();
}
+ } finally {
+ mCallback.get().postReportDropResult();
}
}
@@ -309,8 +285,8 @@
Slog.d(TAG_WM, "cancelDragAndDrop");
}
- synchronized (mWriteLock) {
- mCallback.cancelDragAndDrop(dragToken);
+ mCallback.get().preCancelDragAndDrop(dragToken);
+ try {
synchronized (mService.mWindowMap) {
if (mDragState == null) {
Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()");
@@ -327,6 +303,8 @@
mDragState.mDragResult = false;
mDragState.cancelDragLocked();
}
+ } finally {
+ mCallback.get().postCancelDragAndDrop();
}
}
@@ -338,20 +316,18 @@
* @param newY Y coordinate value in dp in the screen coordinate
*/
void handleMotionEvent(boolean keepHandling, float newX, float newY) {
- synchronized (mWriteLock) {
- synchronized (mService.mWindowMap) {
- if (!dragDropActiveLocked()) {
- // The drag has ended but the clean-up message has not been processed by
- // window manager. Drop events that occur after this until window manager
- // has a chance to clean-up the input handle.
- return;
- }
+ synchronized (mService.mWindowMap) {
+ if (!dragDropActiveLocked()) {
+ // The drag has ended but the clean-up message has not been processed by
+ // window manager. Drop events that occur after this until window manager
+ // has a chance to clean-up the input handle.
+ return;
+ }
- if (keepHandling) {
- mDragState.notifyMoveLocked(newX, newY);
- } else {
- mDragState.notifyDropLocked(newX, newY);
- }
+ if (keepHandling) {
+ mDragState.notifyMoveLocked(newX, newY);
+ } else {
+ mDragState.notifyDropLocked(newX, newY);
}
}
}
@@ -414,12 +390,11 @@
if (DEBUG_DRAG) {
Slog.w(TAG_WM, "Timeout starting drag by win " + win);
}
- synchronized (mWriteLock) {
- synchronized (mService.mWindowMap) {
- // !!! TODO: ANR the app that has failed to start the drag in time
- if (mDragState != null) {
- mDragState.closeLocked();
- }
+
+ synchronized (mService.mWindowMap) {
+ // !!! TODO: ANR the app that has failed to start the drag in time
+ if (mDragState != null) {
+ mDragState.closeLocked();
}
}
break;
@@ -430,13 +405,12 @@
if (DEBUG_DRAG) {
Slog.w(TAG_WM, "Timeout ending drag to win " + win);
}
- synchronized (mWriteLock) {
- synchronized (mService.mWindowMap) {
- // !!! TODO: ANR the drag-receiving app
- if (mDragState != null) {
- mDragState.mDragResult = false;
- mDragState.endDragLocked();
- }
+
+ synchronized (mService.mWindowMap) {
+ // !!! TODO: ANR the drag-receiving app
+ if (mDragState != null) {
+ mDragState.mDragResult = false;
+ mDragState.endDragLocked();
}
}
break;
@@ -455,15 +429,13 @@
}
case MSG_ANIMATION_END: {
- synchronized (mWriteLock) {
- synchronized (mService.mWindowMap) {
- if (mDragState == null) {
- Slog.wtf(TAG_WM, "mDragState unexpectedly became null while " +
- "plyaing animation");
- return;
- }
- mDragState.closeLocked();
+ synchronized (mService.mWindowMap) {
+ if (mDragState == null) {
+ Slog.wtf(TAG_WM, "mDragState unexpectedly became null while " +
+ "plyaing animation");
+ return;
}
+ mDragState.closeLocked();
}
break;
}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 112e62f..b9f437a 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -568,6 +568,14 @@
mToken = token;
}
+ /**
+ * Returns true if it has sent DRAG_STARTED broadcast out but has not been sent DRAG_END
+ * broadcast.
+ */
+ boolean isInProgress() {
+ return mDragInProgress;
+ }
+
private static DragEvent obtainDragEvent(WindowState win, int action,
float x, float y, Object localState,
ClipDescription description, ClipData data,
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 7e29a3a..88b7a11 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -390,12 +390,13 @@
}
}
- final boolean inPositioning = (mService.mTaskPositioner != null);
+ final boolean inPositioning = mService.mTaskPositioningController.isPositioningLocked();
if (inPositioning) {
if (DEBUG_TASK_POSITIONING) {
Log.d(TAG_WM, "Inserting window handle for repositioning");
}
- final InputWindowHandle dragWindowHandle = mService.mTaskPositioner.mDragWindowHandle;
+ final InputWindowHandle dragWindowHandle =
+ mService.mTaskPositioningController.getDragWindowHandleLocked();
if (dragWindowHandle != null) {
addInputWindowHandle(dragWindowHandle);
} else {
diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
new file mode 100644
index 0000000..5fe4565
--- /dev/null
+++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
@@ -0,0 +1,100 @@
+/*
+ * 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.wm;
+
+import android.graphics.Point;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+import android.view.animation.Animation;
+
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+
+/**
+ * Animation that can be executed without holding the window manager lock. See
+ * {@link SurfaceAnimationRunner}.
+ */
+class LocalAnimationAdapter implements AnimationAdapter {
+
+ private final AnimationSpec mSpec;
+ private final SurfaceAnimationRunner mAnimator;
+
+ LocalAnimationAdapter(AnimationSpec spec, SurfaceAnimationRunner animator) {
+ mSpec = spec;
+ mAnimator = animator;
+ }
+
+ @Override
+ public boolean getDetachWallpaper() {
+ return mSpec.getDetachWallpaper();
+ }
+
+ @Override
+ public int getBackgroundColor() {
+ return mSpec.getBackgroundColor();
+ }
+
+ @Override
+ public void startAnimation(SurfaceControl animationLeash, Transaction t,
+ OnAnimationFinishedCallback finishCallback) {
+ mAnimator.startAnimation(mSpec, animationLeash, t,
+ () -> finishCallback.onAnimationFinished(this));
+ }
+
+ @Override
+ public void onAnimationCancelled(SurfaceControl animationLeash) {
+ mAnimator.onAnimationCancelled(animationLeash);
+ }
+
+ @Override
+ public long getDurationHint() {
+ return mSpec.getDuration();
+ }
+
+ /**
+ * Describes how to apply an animation.
+ */
+ interface AnimationSpec {
+
+ /**
+ * @see AnimationAdapter#getDetachWallpaper
+ */
+ default boolean getDetachWallpaper() {
+ return false;
+ }
+
+ /**
+ * @see AnimationAdapter#getBackgroundColor
+ */
+ default int getBackgroundColor() {
+ return 0;
+ }
+
+ /**
+ * @return The duration of the animation.
+ */
+ long getDuration();
+
+ /**
+ * Called when the spec needs to apply the current animation state to the leash.
+ *
+ * @param t The transaction to use to apply a transform.
+ * @param leash The leash to apply the state to.
+ * @param currentPlayTime The current time of the animation.
+ */
+ void apply(Transaction t, SurfaceControl leash, long currentPlayTime);
+ }
+}
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..192d6c8 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());
@@ -365,7 +368,7 @@
long ident = Binder.clearCallingIdentity();
try {
- return mService.startMovingTask(window, startX, startY);
+ return mService.mTaskPositioningController.startMovingTask(window, startX, startY);
} finally {
Binder.restoreCallingIdentity(ident);
}
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/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
new file mode 100644
index 0000000..3ef9b3f
--- /dev/null
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -0,0 +1,231 @@
+/*
+ * 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.wm;
+
+import static android.view.Choreographer.CALLBACK_TRAVERSAL;
+import static android.view.Choreographer.getSfInstance;
+
+import android.animation.AnimationHandler;
+import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.annotation.Nullable;
+import android.util.ArrayMap;
+import android.view.Choreographer;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
+import com.android.server.AnimationThread;
+import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
+
+/**
+ * Class to run animations without holding the window manager lock.
+ */
+class SurfaceAnimationRunner {
+
+ private final Object mLock = new Object();
+
+ /**
+ * Lock for cancelling animations. Must be acquired on it's own, or after acquiring
+ * {@link #mLock}
+ */
+ private final Object mCancelLock = new Object();
+
+ @VisibleForTesting
+ Choreographer mChoreographer;
+
+ private final Runnable mApplyTransactionRunnable = this::applyTransaction;
+ private final AnimationHandler mAnimationHandler;
+ private final Transaction mFrameTransaction;
+ private final AnimatorFactory mAnimatorFactory;
+ private boolean mApplyScheduled;
+
+ @GuardedBy("mLock")
+ @VisibleForTesting
+ final ArrayMap<SurfaceControl, RunningAnimation> mPendingAnimations = new ArrayMap<>();
+
+ @GuardedBy("mLock")
+ @VisibleForTesting
+ final ArrayMap<SurfaceControl, RunningAnimation> mRunningAnimations = new ArrayMap<>();
+
+ SurfaceAnimationRunner() {
+ this(null /* callbackProvider */, null /* animatorFactory */, new Transaction());
+ }
+
+ @VisibleForTesting
+ SurfaceAnimationRunner(@Nullable AnimationFrameCallbackProvider callbackProvider,
+ AnimatorFactory animatorFactory, Transaction frameTransaction) {
+ SurfaceAnimationThread.getHandler().runWithScissors(() -> mChoreographer = getSfInstance(),
+ 0 /* timeout */);
+ mFrameTransaction = frameTransaction;
+ mAnimationHandler = new AnimationHandler();
+ mAnimationHandler.setProvider(callbackProvider != null
+ ? callbackProvider
+ : new SfVsyncFrameCallbackProvider(mChoreographer));
+ mAnimatorFactory = animatorFactory != null
+ ? animatorFactory
+ : SfValueAnimator::new;
+ }
+
+ void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t,
+ Runnable finishCallback) {
+ synchronized (mLock) {
+ final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash,
+ finishCallback);
+ mPendingAnimations.put(animationLeash, runningAnim);
+ mChoreographer.postFrameCallback(this::stepAnimation);
+
+ // Some animations (e.g. move animations) require the initial transform to be applied
+ // immediately.
+ applyTransformation(runningAnim, t, 0 /* currentPlayTime */);
+ }
+ }
+
+ void onAnimationCancelled(SurfaceControl leash) {
+ synchronized (mLock) {
+ if (mPendingAnimations.containsKey(leash)) {
+ mPendingAnimations.remove(leash);
+ return;
+ }
+ final RunningAnimation anim = mRunningAnimations.get(leash);
+ if (anim != null) {
+ mRunningAnimations.remove(leash);
+ synchronized (mCancelLock) {
+ anim.mCancelled = true;
+ }
+ SurfaceAnimationThread.getHandler().post(() -> {
+ anim.mAnim.cancel();
+ applyTransaction();
+ });
+ }
+ }
+ }
+
+ private void startPendingAnimationsLocked() {
+ for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
+ startAnimationLocked(mPendingAnimations.valueAt(i));
+ }
+ mPendingAnimations.clear();
+ }
+
+ private void startAnimationLocked(RunningAnimation a) {
+ final ValueAnimator anim = mAnimatorFactory.makeAnimator();
+
+ // Animation length is already expected to be scaled.
+ anim.overrideDurationScale(1.0f);
+ anim.setDuration(a.mAnimSpec.getDuration());
+ anim.addUpdateListener(animation -> {
+ synchronized (mCancelLock) {
+ if (!a.mCancelled) {
+ applyTransformation(a, mFrameTransaction, anim.getCurrentPlayTime());
+ }
+ }
+
+ // Transaction will be applied in the commit phase.
+ scheduleApplyTransaction();
+ });
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ synchronized (mCancelLock) {
+ if (!a.mCancelled) {
+ mFrameTransaction.show(a.mLeash);
+ }
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ synchronized (mLock) {
+ mRunningAnimations.remove(a.mLeash);
+ synchronized (mCancelLock) {
+ if (!a.mCancelled) {
+ // Post on other thread that we can push final state without jank.
+ AnimationThread.getHandler().post(a.mFinishCallback);
+ }
+ }
+ }
+ }
+ });
+ anim.start();
+ a.mAnim = anim;
+ mRunningAnimations.put(a.mLeash, a);
+ }
+
+ private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
+ a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
+ }
+
+ private void stepAnimation(long frameTimeNanos) {
+ synchronized (mLock) {
+ startPendingAnimationsLocked();
+ }
+ }
+
+ private void scheduleApplyTransaction() {
+ if (!mApplyScheduled) {
+ mChoreographer.postCallback(CALLBACK_TRAVERSAL, mApplyTransactionRunnable,
+ null /* token */);
+ mApplyScheduled = true;
+ }
+ }
+
+ private void applyTransaction() {
+ mFrameTransaction.apply();
+ mApplyScheduled = false;
+ }
+
+ private static final class RunningAnimation {
+ final AnimationSpec mAnimSpec;
+ final SurfaceControl mLeash;
+ final Runnable mFinishCallback;
+ ValueAnimator mAnim;
+
+ @GuardedBy("mCancelLock")
+ private boolean mCancelled;
+
+ RunningAnimation(AnimationSpec animSpec, SurfaceControl leash, Runnable finishCallback) {
+ mAnimSpec = animSpec;
+ mLeash = leash;
+ mFinishCallback = finishCallback;
+ }
+ }
+
+ @VisibleForTesting
+ interface AnimatorFactory {
+ ValueAnimator makeAnimator();
+ }
+
+ /**
+ * Value animator that uses sf-vsync signal to tick.
+ */
+ private class SfValueAnimator extends ValueAnimator {
+
+ SfValueAnimator() {
+ setFloatValues(0f, 1f);
+ }
+
+ @Override
+ public AnimationHandler getAnimationHandler() {
+ return mAnimationHandler;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationThread.java b/services/core/java/com/android/server/wm/SurfaceAnimationThread.java
new file mode 100644
index 0000000..0d3afc0
--- /dev/null
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationThread.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.server.wm;
+
+import static android.os.Process.THREAD_PRIORITY_DISPLAY;
+
+import android.os.Handler;
+import android.os.Trace;
+
+import com.android.server.ServiceThread;
+
+/**
+ * Thread for running {@link SurfaceAnimationRunner} that does not hold the window manager lock.
+ */
+public final class SurfaceAnimationThread extends ServiceThread {
+ private static SurfaceAnimationThread sInstance;
+ private static Handler sHandler;
+
+ private SurfaceAnimationThread() {
+ super("android.anim.lf", THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
+ }
+
+ private static void ensureThreadLocked() {
+ if (sInstance == null) {
+ sInstance = new SurfaceAnimationThread();
+ sInstance.start();
+ sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER);
+ sHandler = new Handler(sInstance.getLooper());
+ }
+ }
+
+ public static SurfaceAnimationThread get() {
+ synchronized (SurfaceAnimationThread.class) {
+ ensureThreadLocked();
+ return sInstance;
+ }
+ }
+
+ public static Handler getHandler() {
+ synchronized (SurfaceAnimationThread.class) {
+ ensureThreadLocked();
+ return sHandler;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
new file mode 100644
index 0000000..e165211
--- /dev/null
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -0,0 +1,331 @@
+/*
+ * 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.wm;
+
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+
+import java.io.PrintWriter;
+
+/**
+ * A class that can run animations on objects that have a set of child surfaces. We do this by
+ * reparenting all child surfaces of an object onto a new surface, called the "Leash". The Leash
+ * gets attached in the surface hierarchy where the the children were attached to. We then hand off
+ * the Leash to the component handling the animation, which is specified by the
+ * {@link AnimationAdapter}. When the animation is done animating, our callback to finish the
+ * animation will be invoked, at which we reparent the children back to the original parent.
+ */
+class SurfaceAnimator {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "SurfaceAnimator" : TAG_WM;
+ private final WindowManagerService mService;
+ private AnimationAdapter mAnimation;
+ private SurfaceControl mLeash;
+ private final Animatable mAnimatable;
+ private final OnAnimationFinishedCallback mInnerAnimationFinishedCallback;
+ private final Runnable mAnimationFinishedCallback;
+ private boolean mAnimationStartDelayed;
+
+ /**
+ * @param animatable The object to animate.
+ * @param animationFinishedCallback Callback to invoke when an animation has finished running.
+ */
+ SurfaceAnimator(Animatable animatable, Runnable animationFinishedCallback,
+ WindowManagerService service) {
+ mAnimatable = animatable;
+ mService = service;
+ mAnimationFinishedCallback = animationFinishedCallback;
+ mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback);
+ }
+
+ private OnAnimationFinishedCallback getFinishedCallback(Runnable animationFinishedCallback) {
+ return anim -> {
+ synchronized (mService.mWindowMap) {
+ if (anim != mAnimation) {
+ // Callback was from another animation - ignore.
+ return;
+ }
+
+ final Transaction t = new Transaction();
+ SurfaceControl.openTransaction();
+ try {
+ reset(t);
+ animationFinishedCallback.run();
+ } finally {
+ // TODO: This should use pendingTransaction eventually, but right now things
+ // happening on the animation finished callback are happening on the global
+ // transaction.
+ SurfaceControl.mergeToGlobalTransaction(t);
+ SurfaceControl.closeTransaction();
+ }
+ }
+ };
+ }
+
+ /**
+ * Starts an animation.
+ *
+ * @param anim The object that bridges the controller, {@link SurfaceAnimator}, with the
+ * component responsible for running the animation. It runs the animation with
+ * {@link AnimationAdapter#startAnimation} once the hierarchy with
+ * the Leash has been set up.
+ * @param hidden Whether the container holding the child surfaces is currently visible or not.
+ * This is important as it will start with the leash hidden or visible before
+ * handing it to the component that is responsible to run the animation.
+ */
+ void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
+ cancelAnimation(t, true /* restarting */);
+ mAnimation = anim;
+ final SurfaceControl surface = mAnimatable.getSurfaceControl();
+ if (surface == null) {
+ Slog.w(TAG, "Unable to start animation, surface is null or no children.");
+ cancelAnimation();
+ return;
+ }
+ mLeash = createAnimationLeash(surface, t,
+ mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), hidden);
+ mAnimatable.onAnimationLeashCreated(t, mLeash);
+ if (mAnimationStartDelayed) {
+ if (DEBUG_ANIM) Slog.i(TAG, "Animation start delayed");
+ return;
+ }
+ mAnimation.startAnimation(mLeash, t, mInnerAnimationFinishedCallback);
+ }
+
+ /**
+ * Begins with delaying all animations to start. Any subsequent call to {@link #startAnimation}
+ * will not start the animation until {@link #endDelayingAnimationStart} is called. When an
+ * animation start is being delayed, the animator is considered animating already.
+ */
+ void startDelayingAnimationStart() {
+
+ // We only allow delaying animation start we are not currently animating
+ if (!isAnimating()) {
+ mAnimationStartDelayed = true;
+ }
+ }
+
+ /**
+ * See {@link #startDelayingAnimationStart}.
+ */
+ void endDelayingAnimationStart() {
+ final boolean delayed = mAnimationStartDelayed;
+ mAnimationStartDelayed = false;
+ if (delayed && mAnimation != null) {
+ mAnimation.startAnimation(mLeash, mAnimatable.getPendingTransaction(),
+ mInnerAnimationFinishedCallback);
+ mAnimatable.commitPendingTransaction();
+ }
+ }
+
+ /**
+ * @return Whether we are currently running an animation, or we have a pending animation that
+ * is waiting to be started with {@link #endDelayingAnimationStart}
+ */
+ boolean isAnimating() {
+ return mAnimation != null;
+ }
+
+ /**
+ * @return The current animation spec if we are running an animation, or {@code null} otherwise.
+ */
+ AnimationAdapter getAnimation() {
+ return mAnimation;
+ }
+
+ /**
+ * Cancels any currently running animation.
+ */
+ void cancelAnimation() {
+ cancelAnimation(mAnimatable.getPendingTransaction(), false /* restarting */);
+ mAnimatable.commitPendingTransaction();
+ }
+
+ /**
+ * Sets the layer of the surface.
+ * <p>
+ * When the layer of the surface needs to be adjusted, we need to set it on the leash if the
+ * surface is reparented to the leash. This method takes care of that.
+ */
+ void setLayer(Transaction t, int layer) {
+ t.setLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), layer);
+ }
+
+ /**
+ * Sets the surface to be relatively layered.
+ *
+ * @see #setLayer
+ */
+ void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
+ t.setRelativeLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), relativeTo, layer);
+ }
+
+ /**
+ * Reparents the surface.
+ *
+ * @see #setLayer
+ */
+ void reparent(Transaction t, SurfaceControl newParent) {
+ t.reparent(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), newParent.getHandle());
+ }
+
+ /**
+ * @return True if the surface is attached to the leash; false otherwise.
+ */
+ boolean hasLeash() {
+ return mLeash != null;
+ }
+
+ private void cancelAnimation(Transaction t, boolean restarting) {
+ if (DEBUG_ANIM) Slog.i(TAG, "Cancelling animation restarting=" + restarting);
+ final SurfaceControl leash = mLeash;
+ final AnimationAdapter animation = mAnimation;
+ reset(t);
+ if (animation != null) {
+ if (!mAnimationStartDelayed) {
+ animation.onAnimationCancelled(leash);
+ }
+ if (!restarting) {
+ mAnimationFinishedCallback.run();
+ }
+ }
+ if (!restarting) {
+ mAnimationStartDelayed = false;
+ }
+ }
+
+ private void reset(Transaction t) {
+ final SurfaceControl surface = mAnimatable.getSurfaceControl();
+ final SurfaceControl parent = mAnimatable.getParentSurfaceControl();
+
+ // If the surface was destroyed, we don't care to reparent it back.
+ final boolean destroy = mLeash != null && surface != null && parent != null;
+ if (destroy) {
+ if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent");
+ t.reparent(surface, parent.getHandle());
+ }
+ if (mLeash != null) {
+ mAnimatable.destroyAfterPendingTransaction(mLeash);
+ }
+ mLeash = null;
+ mAnimation = null;
+
+ // Make sure to inform the animatable after the leash was destroyed.
+ if (destroy) {
+ mAnimatable.onAnimationLeashDestroyed(t);
+ }
+ }
+
+ private SurfaceControl createAnimationLeash(SurfaceControl surface, Transaction t, int width,
+ int height, boolean hidden) {
+ if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash");
+ final SurfaceControl.Builder builder = mAnimatable.makeAnimationLeash()
+ .setName(surface + " - animation-leash")
+ .setSize(width, height);
+ final SurfaceControl leash = builder.build();
+ if (!hidden) {
+ t.show(leash);
+ }
+ t.reparent(surface, leash.getHandle());
+ return leash;
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("mAnimation="); pw.print(mAnimation);
+ pw.print(" mLeash="); pw.println(mLeash);
+ }
+
+ /**
+ * Callback to be passed into {@link AnimationAdapter#startAnimation} to be invoked by the
+ * component that is running the animation when the animation is finished.
+ */
+ interface OnAnimationFinishedCallback {
+ void onAnimationFinished(AnimationAdapter anim);
+ }
+
+ /**
+ * Interface to be animated by {@link SurfaceAnimator}.
+ */
+ interface Animatable {
+
+ /**
+ * @return The pending transaction that will be committed in the next frame.
+ */
+ @NonNull Transaction getPendingTransaction();
+
+ /**
+ * Schedules a commit of the pending transaction.
+ */
+ void commitPendingTransaction();
+
+ /**
+ * Called when the was created.
+ *
+ * @param t The transaction to use to apply any necessary changes.
+ * @param leash The leash that was created.
+ */
+ void onAnimationLeashCreated(Transaction t, SurfaceControl leash);
+
+ /**
+ * Called when the leash is being destroyed, and the surface was reparented back to the
+ * original parent.
+ *
+ * @param t The transaction to use to apply any necessary changes.
+ */
+ void onAnimationLeashDestroyed(Transaction t);
+
+ /**
+ * Destroy a given surface after executing {@link #getPendingTransaction}.
+ *
+ * @see WindowContainer#destroyAfterPendingTransaction
+ */
+ void destroyAfterPendingTransaction(SurfaceControl surface);
+
+ /**
+ * @return A new surface to be used for the animation leash, inserted at the correct
+ * position in the hierarchy.
+ */
+ SurfaceControl.Builder makeAnimationLeash();
+
+ /**
+ * @return The surface of the object to be animated.
+ */
+ @Nullable SurfaceControl getSurfaceControl();
+
+ /**
+ * @return The parent of the surface object to be animated.
+ */
+ @Nullable SurfaceControl getParentSurfaceControl();
+
+ /**
+ * @return The width of the surface to be animated.
+ */
+ int getSurfaceWidth();
+
+ /**
+ * @return The height of the surface to be animated.
+ */
+ int getSurfaceHeight();
+ }
+}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 8aa129a..244eb66 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -22,7 +22,6 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.res.Configuration.EMPTY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static com.android.server.EventLogTags.WM_TASK_REMOVED;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
@@ -43,7 +42,6 @@
import android.util.EventLog;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
-import android.view.DisplayInfo;
import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
@@ -59,7 +57,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 +99,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);
@@ -163,7 +160,7 @@
boolean shouldDeferRemoval() {
// TODO: This should probably return false if mChildren.isEmpty() regardless if the stack
// is animating...
- return hasWindowsAlive() && mStack.isAnimating();
+ return hasWindowsAlive() && mStack.isSelfOrChildAnimating();
}
@Override
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 87d0a40..ca9f3a9 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -16,15 +16,11 @@
package com.android.server.wm;
-import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.RESIZE_MODE_USER;
import static android.app.ActivityManager.RESIZE_MODE_USER_FORCED;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.dipToPixel;
@@ -44,7 +40,6 @@
import android.view.BatchedInputEventReceiver;
import android.view.Choreographer;
import android.view.Display;
-import android.view.DisplayInfo;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
new file mode 100644
index 0000000..bb5706c
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -0,0 +1,159 @@
+/*
+ * 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.wm;
+
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.annotation.Nullable;
+import android.app.IActivityManager;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.Display;
+import android.view.IWindow;
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.input.InputManagerService;
+import com.android.server.input.InputWindowHandle;
+
+/**
+ * Controller for task positioning by drag.
+ */
+class TaskPositioningController {
+ private final WindowManagerService mService;
+ private final InputManagerService mInputManager;
+ private final InputMonitor mInputMonitor;
+ private final IActivityManager mActivityManager;
+
+ @GuardedBy("WindowManagerSerivce.mWindowMap")
+ private @Nullable TaskPositioner mTaskPositioner;
+
+ boolean isPositioningLocked() {
+ return mTaskPositioner != null;
+ }
+
+ InputWindowHandle getDragWindowHandleLocked() {
+ return mTaskPositioner != null ? mTaskPositioner.mDragWindowHandle : null;
+ }
+
+ TaskPositioningController(WindowManagerService service, InputManagerService inputManager,
+ InputMonitor inputMonitor, IActivityManager activityManager) {
+ mService = service;
+ mInputMonitor = inputMonitor;
+ mInputManager = inputManager;
+ mActivityManager = activityManager;
+ }
+
+ boolean startMovingTask(IWindow window, float startX, float startY) {
+ WindowState win = null;
+ synchronized (mService.mWindowMap) {
+ win = mService.windowForClientLocked(null, window, false);
+ // win shouldn't be null here, pass it down to startPositioningLocked
+ // to get warning if it's null.
+ if (!startPositioningLocked(
+ win, false /*resize*/, false /*preserveOrientation*/, startX, startY)) {
+ return false;
+ }
+ }
+ try {
+ mActivityManager.setFocusedTask(win.getTask().mTaskId);
+ } catch(RemoteException e) {}
+ return true;
+ }
+
+ void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
+ int taskId = -1;
+ synchronized (mService.mWindowMap) {
+ final Task task = displayContent.findTaskForResizePoint(x, y);
+ if (task != null) {
+ if (!startPositioningLocked(task.getTopVisibleAppMainWindow(), true /*resize*/,
+ task.preserveOrientationOnResize(), x, y)) {
+ return;
+ }
+ taskId = task.mTaskId;
+ } else {
+ taskId = displayContent.taskIdFromPoint(x, y);
+ }
+ }
+ if (taskId >= 0) {
+ try {
+ mActivityManager.setFocusedTask(taskId);
+ } catch(RemoteException e) {}
+ }
+ }
+
+ private boolean startPositioningLocked(WindowState win, boolean resize,
+ boolean preserveOrientation, float startX, float startY) {
+ if (DEBUG_TASK_POSITIONING)
+ Slog.d(TAG_WM, "startPositioningLocked: "
+ + "win=" + win + ", resize=" + resize + ", preserveOrientation="
+ + preserveOrientation + ", {" + startX + ", " + startY + "}");
+
+ if (win == null || win.getAppToken() == null) {
+ Slog.w(TAG_WM, "startPositioningLocked: Bad window " + win);
+ return false;
+ }
+ if (win.mInputChannel == null) {
+ Slog.wtf(TAG_WM, "startPositioningLocked: " + win + " has no input channel, "
+ + " probably being removed");
+ return false;
+ }
+
+ final DisplayContent displayContent = win.getDisplayContent();
+ if (displayContent == null) {
+ Slog.w(TAG_WM, "startPositioningLocked: Invalid display content " + win);
+ return false;
+ }
+
+ Display display = displayContent.getDisplay();
+ mTaskPositioner = new TaskPositioner(mService);
+ mTaskPositioner.register(displayContent);
+ mInputMonitor.updateInputWindowsLw(true /*force*/);
+
+ // We need to grab the touch focus so that the touch events during the
+ // resizing/scrolling are not sent to the app. 'win' is the main window
+ // of the app, it may not have focus since there might be other windows
+ // on top (eg. a dialog window).
+ WindowState transferFocusFromWin = win;
+ if (mService.mCurrentFocus != null && mService.mCurrentFocus != win
+ && mService.mCurrentFocus.mAppToken == win.mAppToken) {
+ transferFocusFromWin = mService.mCurrentFocus;
+ }
+ if (!mInputManager.transferTouchFocus(
+ transferFocusFromWin.mInputChannel, mTaskPositioner.mServerChannel)) {
+ Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
+ mTaskPositioner.unregister();
+ mTaskPositioner = null;
+ mInputMonitor.updateInputWindowsLw(true /*force*/);
+ return false;
+ }
+
+ mTaskPositioner.startDrag(win, resize, preserveOrientation, startX, startY);
+ return true;
+ }
+
+ void finishPositioning() {
+ if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishPositioning");
+
+ synchronized (mService.mWindowMap) {
+ if (mTaskPositioner != null) {
+ mTaskPositioner.unregister();
+ mTaskPositioner = null;
+ mInputMonitor.updateInputWindowsLw(true /*force*/);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 43a0893..c091157 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -236,7 +236,7 @@
return null;
}
return new TaskSnapshot(buffer, top.getConfiguration().orientation,
- minRect(mainWindow.mContentInsets, mainWindow.mStableInsets),
+ getInsetsFromTaskBounds(mainWindow, task),
isLowRamDevice /* reduced */, scaleFraction /* scale */);
}
@@ -244,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..9946c6a 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(
@@ -938,7 +935,7 @@
@Override
void removeIfPossible() {
- if (isAnimating()) {
+ if (isSelfOrChildAnimating()) {
mDeferRemoval = true;
return;
}
@@ -1117,12 +1114,12 @@
return false;
}
- final Rect displayContentRect = mTmpRect;
+ final Rect displayStableRect = mTmpRect;
final Rect contentBounds = mTmpRect2;
// Calculate the content bounds excluding the area occupied by IME
- getDisplayContent().getContentRect(displayContentRect);
- contentBounds.set(displayContentRect);
+ getDisplayContent().getStableRect(displayStableRect);
+ contentBounds.set(displayStableRect);
int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top);
imeTop += imeWin.getGivenContentInsetsLw().top;
@@ -1130,7 +1127,7 @@
contentBounds.bottom = imeTop;
}
- final int yOffset = displayContentRect.bottom - contentBounds.bottom;
+ final int yOffset = displayStableRect.bottom - contentBounds.bottom;
final int dividerWidth =
getDisplayContent().mDividerControllerLocked.getContentWidth();
@@ -1142,7 +1139,7 @@
// occluded by IME. We shift its bottom up by the height of the IME, but
// leaves at least 30% of the top stack visible.
final int minTopStackBottom =
- getMinTopStackBottom(displayContentRect, getRawBounds().bottom);
+ getMinTopStackBottom(displayStableRect, getRawBounds().bottom);
final int bottom = Math.max(
getRawBounds().bottom - yOffset + dividerWidth - dividerWidthInactive,
minTopStackBottom);
@@ -1162,7 +1159,7 @@
final int topBeforeImeAdjust =
getRawBounds().top - dividerWidth + dividerWidthInactive;
final int minTopStackBottom =
- getMinTopStackBottom(displayContentRect,
+ getMinTopStackBottom(displayStableRect,
getRawBounds().top - dividerWidth);
final int top = Math.max(
getRawBounds().top - yOffset, minTopStackBottom + dividerWidthInactive);
@@ -1646,7 +1643,7 @@
/** Returns true if a removal action is still being deferred. */
boolean checkCompleteDeferredRemoval() {
- if (isAnimating()) {
+ if (isSelfOrChildAnimating()) {
return true;
}
if (mDeferRemoval) {
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/services/core/java/com/android/server/wm/TransactionFactory.java
similarity index 70%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to services/core/java/com/android/server/wm/TransactionFactory.java
index 353728a..067f083 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/services/core/java/com/android/server/wm/TransactionFactory.java
@@ -11,15 +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.server.timezone;
+package com.android.server.wm;
+
+import android.view.SurfaceControl.Transaction;
/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
+ * Helper class to inject custom transaction objects into window manager.
*/
-interface ClockHelper {
+interface TransactionFactory {
+ Transaction make();
+};
- long currentTimestamp();
-}
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index a12c0e5..3389f71 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -115,7 +115,7 @@
void startAnimation(Animation anim) {
for (int ndx = mChildren.size() - 1; ndx >= 0; ndx--) {
final WindowState windowState = mChildren.get(ndx);
- windowState.mWinAnimator.setAnimation(anim);
+ windowState.startAnimation(anim);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
new file mode 100644
index 0000000..bb25297
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@@ -0,0 +1,70 @@
+/*
+ * 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.wm;
+
+import android.graphics.Point;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+
+import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
+
+/**
+ * Animation spec for regular window animations.
+ */
+public class WindowAnimationSpec implements AnimationSpec {
+
+ private Animation mAnimation;
+ private final Point mPosition = new Point();
+ private final ThreadLocal<TmpValues> mThreadLocalTmps = ThreadLocal.withInitial(TmpValues::new);
+
+ public WindowAnimationSpec(Animation animation, Point position) {
+ mAnimation = animation;
+ mPosition.set(position.x, position.y);
+ }
+
+ @Override
+ public boolean getDetachWallpaper() {
+ return mAnimation.getDetachWallpaper();
+ }
+
+ @Override
+ public int getBackgroundColor() {
+ return mAnimation.getBackgroundColor();
+ }
+
+ @Override
+ public long getDuration() {
+ return mAnimation.computeDurationHint();
+ }
+
+ @Override
+ public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
+ final TmpValues tmp = mThreadLocalTmps.get();
+ tmp.transformation.clear();
+ mAnimation.getTransformation(currentPlayTime, tmp.transformation);
+ tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
+ t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats);
+ t.setAlpha(leash, tmp.transformation.getAlpha());
+ }
+
+ private static class TmpValues {
+ final Transformation transformation = new Transformation();
+ final float[] floats = new float[9];
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 6467582..b2b6119 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -19,20 +19,30 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
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;
import android.content.res.Configuration;
+import android.graphics.PixelFormat.Opacity;
+import android.util.Slog;
import android.view.MagnificationSpec;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.Builder;
import android.view.SurfaceSession;
import android.util.Pools;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.util.ToBooleanFunction;
+import com.android.internal.util.ToBooleanFunction;
+import com.android.server.wm.SurfaceAnimator.Animatable;
+
+import java.io.PrintWriter;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.function.Consumer;
@@ -45,7 +55,9 @@
* changes are made to this class.
*/
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
- implements Comparable<WindowContainer> {
+ implements Comparable<WindowContainer>, Animatable {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainer" : TAG_WM;
static final int POSITION_TOP = Integer.MAX_VALUE;
static final int POSITION_BOTTOM = Integer.MIN_VALUE;
@@ -55,7 +67,7 @@
* For removing or setting new parent {@link #setParent} should be used, because it also
* performs configuration updates based on new parent's settings.
*/
- private WindowContainer mParent = null;
+ private WindowContainer<WindowContainer> mParent = null;
// List of children for this window container. List is in z-order as the children appear on
// screen with the top-most window container at the tail of the list.
@@ -68,21 +80,30 @@
new Pools.SynchronizedPool<>(3);
// The owner/creator for this container. No controller if null.
- WindowContainerController mController;
+ 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();
+ protected final Transaction mPendingTransaction;
+ protected final SurfaceAnimator mSurfaceAnimator;
+ protected final WindowManagerService mService;
+
+ WindowContainer(WindowManagerService service) {
+ mService = service;
+ mPendingTransaction = service.mTransactionFactory.make();
+ mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, service);
+ }
@Override
final protected WindowContainer getParent() {
return mParent;
}
-
@Override
protected int getChildCount() {
return mChildren.size();
@@ -93,7 +114,7 @@
return mChildren.get(index);
}
- final protected void setParent(WindowContainer parent) {
+ final protected void setParent(WindowContainer<WindowContainer> parent) {
mParent = parent;
// Removing parent usually means that we've detached this entity to destroy it or to attach
// to another parent. In both cases we don't need to update the configuration now.
@@ -115,14 +136,18 @@
if (mParent == null) {
return;
}
+
if (mSurfaceControl == null) {
// If we don't yet have a surface, but we now have a parent, we should
// build a surface.
mSurfaceControl = makeSurface().build();
getPendingTransaction().show(mSurfaceControl);
} else {
- // If we have a surface but a new parent, we just need to perform a reparent.
- getPendingTransaction().reparent(mSurfaceControl, mParent.mSurfaceControl.getHandle());
+ // If we have a surface but a new parent, we just need to perform a reparent. Go through
+ // surface animator such that hierarchy is preserved when animating, i.e.
+ // mSurfaceControl stays attached to the leash and we just reparent the leash to the
+ // new parent.
+ mSurfaceAnimator.reparent(getPendingTransaction(), mParent.mSurfaceControl);
}
// Either way we need to ask the parent to assign us a Z-order.
@@ -131,8 +156,8 @@
}
// Temp. holders for a chain of containers we are currently processing.
- private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList();
- private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList();
+ private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList<>();
+ private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList<>();
/**
* Adds the input window container has a child of this container in order based on the input
@@ -206,7 +231,7 @@
@CallSuper
void removeImmediately() {
while (!mChildren.isEmpty()) {
- final WindowContainer child = mChildren.peekLast();
+ final E child = mChildren.peekLast();
child.removeImmediately();
// Need to do this after calling remove on the child because the child might try to
// remove/detach itself from its parent which will cause an exception if we remove
@@ -393,16 +418,40 @@
}
}
- boolean isAnimating() {
+ /**
+ * @return Whether our own container is running an animation or any child, no matter how deep in
+ * the hierarchy, is animating.
+ */
+ boolean isSelfOrChildAnimating() {
+ if (isSelfAnimating()) {
+ return true;
+ }
for (int j = mChildren.size() - 1; j >= 0; j--) {
final WindowContainer wc = mChildren.get(j);
- if (wc.isAnimating()) {
+ if (wc.isSelfOrChildAnimating()) {
return true;
}
}
return false;
}
+ /**
+ * @return Whether our own container is running an animation or our parent is animating. This
+ * doesn't consider whether children are animating.
+ */
+ boolean isAnimating() {
+
+ // We are animating if we ourselves are animating or if our parent is animating.
+ return isSelfAnimating() || mParent != null && mParent.isAnimating();
+ }
+
+ /**
+ * @return Whether our own container running an animation at the moment.
+ */
+ boolean isSelfAnimating() {
+ return mSurfaceAnimator.isAnimating();
+ }
+
void sendAppVisibilityToClients() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
@@ -735,6 +784,15 @@
.setParent(mSurfaceControl);
}
+ @Override
+ public SurfaceControl getParentSurfaceControl() {
+ final WindowContainer parent = getParent();
+ if (parent == null) {
+ return null;
+ }
+ return parent.getSurfaceControl();
+ }
+
/**
* @return Whether this WindowContainer should be magnified by the accessibility magnifier.
*/
@@ -755,34 +813,52 @@
}
void assignLayer(Transaction t, int layer) {
- if (mSurfaceControl != null) {
- t.setLayer(mSurfaceControl, layer);
+ final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
+ if (mSurfaceControl != null && changed) {
+
+ // Route through surface animator to accommodate that our surface control might be
+ // attached to the leash, and leash is attached to parent container.
+ mSurfaceAnimator.setLayer(t, layer);
+ mLastLayer = layer;
+ mLastRelativeToLayer = null;
+ }
+ }
+
+ void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
+ final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo;
+ if (mSurfaceControl != null && changed) {
+
+ // Route through surface animator to accommodate that our surface control might be
+ // attached to the leash, and leash is attached to parent container.
+ mSurfaceAnimator.setRelativeLayer(t, 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() {
@@ -809,6 +885,7 @@
final long token = proto.start(fieldId);
super.writeToProto(proto, CONFIGURATION_CONTAINER, trim);
proto.write(ORIENTATION, mOrientation);
+ proto.write(VISIBLE, isVisible());
proto.end(token);
}
@@ -876,7 +953,8 @@
}
}
- SurfaceControl getSurfaceControl() {
+ @Override
+ public SurfaceControl getSurfaceControl() {
return mSurfaceControl;
}
@@ -886,13 +964,105 @@
* rather than an intentional design, so please take care when
* expanding use.
*/
- void destroyAfterPendingTransaction(SurfaceControl surface) {
+ @Override
+ public void destroyAfterPendingTransaction(SurfaceControl surface) {
if (mParent != null) {
mParent.destroyAfterPendingTransaction(surface);
}
}
-
- Transaction getPendingTransaction() {
+
+ @Override
+ public Transaction getPendingTransaction() {
return mPendingTransaction;
}
+
+ /**
+ * Starts an animation on the container.
+ *
+ * @param anim The animation to run.
+ * @param hidden Whether our container is currently hidden. TODO This should use isVisible at
+ * some point but the meaning is too weird to work for all containers.
+ */
+ void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
+ if (DEBUG_ANIM) Slog.v(TAG, "Starting animation on " + this + ": " + anim);
+
+ // TODO: This should use isVisible() but because isVisible has a really weird meaning at
+ // the moment this doesn't work for all animatable window containers.
+ mSurfaceAnimator.startAnimation(t, anim, hidden);
+ }
+
+ void cancelAnimation() {
+ mSurfaceAnimator.cancelAnimation();
+ }
+
+ @Override
+ public Builder makeAnimationLeash() {
+ return makeSurface();
+ }
+
+ @Override
+ public void commitPendingTransaction() {
+ scheduleAnimation();
+ }
+
+ private void reassignLayer(Transaction t) {
+ final WindowContainer parent = getParent();
+ if (parent != null) {
+ parent.assignChildLayers(t);
+ }
+ }
+
+ @Override
+ public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
+ reassignLayer(t);
+ }
+
+ @Override
+ public void onAnimationLeashDestroyed(Transaction t) {
+ reassignLayer(t);
+ }
+
+ /**
+ * Called when an animation has finished running.
+ */
+ protected void onAnimationFinished() {
+ }
+
+ /**
+ * @return The currently running animation, if any, or {@code null} otherwise.
+ */
+ AnimationAdapter getAnimation() {
+ return mSurfaceAnimator.getAnimation();
+ }
+
+ /**
+ * @see SurfaceAnimator#startDelayingAnimationStart
+ */
+ void startDelayingAnimationStart() {
+ mSurfaceAnimator.startDelayingAnimationStart();
+ }
+
+ /**
+ * @see SurfaceAnimator#endDelayingAnimationStart
+ */
+ void endDelayingAnimationStart() {
+ mSurfaceAnimator.endDelayingAnimationStart();
+ }
+
+ @Override
+ public int getSurfaceWidth() {
+ return mSurfaceControl.getWidth();
+ }
+
+ @Override
+ public int getSurfaceHeight() {
+ return mSurfaceControl.getHeight();
+ }
+
+ void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+ if (mSurfaceAnimator.isAnimating()) {
+ pw.print(prefix); pw.println("ContainerAnimator:");
+ mSurfaceAnimator.dump(pw, prefix + " ");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 036f7b0..62d2e7d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -151,23 +151,38 @@
*/
public interface IDragDropCallback {
/**
- * Called when drag operation is started.
+ * Called when drag operation is starting.
*/
- default boolean performDrag(IWindow window, IBinder dragToken,
+ default boolean prePerformDrag(IWindow window, IBinder dragToken,
int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
ClipData data) {
return true;
}
/**
- * Called when drop result is reported.
+ * Called when drag operation is started.
*/
- default void reportDropResult(IWindow window, boolean consumed) {}
+ default void postPerformDrag() {}
/**
- * Called when drag operation is cancelled.
+ * Called when drop result is being reported.
*/
- default void cancelDragAndDrop(IBinder dragToken) {}
+ default void preReportDropResult(IWindow window, boolean consumed) {}
+
+ /**
+ * Called when drop result was reported.
+ */
+ default void postReportDropResult() {}
+
+ /**
+ * Called when drag operation is being cancelled.
+ */
+ default void preCancelDragAndDrop(IBinder dragToken) {}
+
+ /**
+ * Called when drag operation was cancelled.
+ */
+ default void postCancelDragAndDrop() {}
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 82f842c..7a3ba74 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;
@@ -720,8 +725,6 @@
}
}
- boolean mAnimateWallpaperWithTarget;
-
// TODO: Move to RootWindowContainer
AppWindowToken mFocusedApp = null;
@@ -750,7 +753,7 @@
// Whether or not a layout can cause a wake up when theater mode is enabled.
boolean mAllowTheaterModeWakeFromLayout;
- TaskPositioner mTaskPositioner;
+ final TaskPositioningController mTaskPositioningController;
final DragDropController mDragDropController;
// For frozen screen animations.
@@ -764,6 +767,7 @@
int mTransactionSequence;
final WindowAnimator mAnimator;
+ final SurfaceAnimationRunner mSurfaceAnimationRunner;
final BoundsAnimationController mBoundsAnimationController;
@@ -771,6 +775,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 +806,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 +1072,8 @@
filter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiver(mBroadcastReceiver, filter);
+ mLatencyTracker = LatencyTracker.getInstance(context);
+
mSettingsObserver = new SettingsObserver();
mHoldingScreenWakeLock = mPowerManager.newWakeLock(
@@ -1077,10 +1081,13 @@
mHoldingScreenWakeLock.setReferenceCounted(false);
mAnimator = new WindowAnimator(this);
+ mSurfaceAnimationRunner = new SurfaceAnimationRunner();
mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
+ mTaskPositioningController =
+ new TaskPositioningController(this, mInputManager, mInputMonitor, mActivityManager);
mDragDropController = new DragDropController(this, mH.getLooper());
LocalServices.addService(WindowManagerInternal.class, new LocalService());
@@ -1129,9 +1136,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 +1473,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 +1501,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 +1853,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 +1971,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 +1987,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 +2088,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 +2136,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(
@@ -2178,18 +2180,15 @@
if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
focusMayChange = isDefaultDisplay;
win.mAnimatingExit = true;
- win.mWinAnimator.mAnimating = true;
} else if (win.mWinAnimator.isAnimationSet()) {
// Currently in a hide animation... turn this into
// an exit.
win.mAnimatingExit = true;
- win.mWinAnimator.mAnimating = true;
} else if (win.getDisplayContent().mWallpaperController.isWallpaperTarget(win)) {
// If the wallpaper is currently behind this
// window, we need to change both of them inside
// of a transaction to avoid artifacts.
win.mAnimatingExit = true;
- win.mWinAnimator.mAnimating = true;
} else {
if (mInputMethodWindow == win) {
setInputMethodWindowLocked(null);
@@ -3046,11 +3045,6 @@
}
@Override
- public boolean inKeyguardRestrictedInputMode() {
- return mPolicy.inKeyguardRestrictedKeyInputMode();
- }
-
- @Override
public boolean isKeyguardLocked() {
return mPolicy.isKeyguardLocked();
}
@@ -4445,107 +4439,6 @@
}
}
- boolean startMovingTask(IWindow window, float startX, float startY) {
- WindowState win = null;
- synchronized (mWindowMap) {
- win = windowForClientLocked(null, window, false);
- // win shouldn't be null here, pass it down to startPositioningLocked
- // to get warning if it's null.
- if (!startPositioningLocked(
- win, false /*resize*/, false /*preserveOrientation*/, startX, startY)) {
- return false;
- }
- }
- try {
- mActivityManager.setFocusedTask(win.getTask().mTaskId);
- } catch(RemoteException e) {}
- return true;
- }
-
- private void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
- int taskId = -1;
- synchronized (mWindowMap) {
- final Task task = displayContent.findTaskForResizePoint(x, y);
- if (task != null) {
- if (!startPositioningLocked(task.getTopVisibleAppMainWindow(), true /*resize*/,
- task.preserveOrientationOnResize(), x, y)) {
- return;
- }
- taskId = task.mTaskId;
- } else {
- taskId = displayContent.taskIdFromPoint(x, y);
- }
- }
- if (taskId >= 0) {
- try {
- mActivityManager.setFocusedTask(taskId);
- } catch(RemoteException e) {}
- }
- }
-
- private boolean startPositioningLocked(WindowState win, boolean resize,
- boolean preserveOrientation, float startX, float startY) {
- if (DEBUG_TASK_POSITIONING)
- Slog.d(TAG_WM, "startPositioningLocked: "
- + "win=" + win + ", resize=" + resize + ", preserveOrientation="
- + preserveOrientation + ", {" + startX + ", " + startY + "}");
-
- if (win == null || win.getAppToken() == null) {
- Slog.w(TAG_WM, "startPositioningLocked: Bad window " + win);
- return false;
- }
- if (win.mInputChannel == null) {
- Slog.wtf(TAG_WM, "startPositioningLocked: " + win + " has no input channel, "
- + " probably being removed");
- return false;
- }
-
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent == null) {
- Slog.w(TAG_WM, "startPositioningLocked: Invalid display content " + win);
- return false;
- }
-
- Display display = displayContent.getDisplay();
- mTaskPositioner = new TaskPositioner(this);
- mTaskPositioner.register(displayContent);
- mInputMonitor.updateInputWindowsLw(true /*force*/);
-
- // We need to grab the touch focus so that the touch events during the
- // resizing/scrolling are not sent to the app. 'win' is the main window
- // of the app, it may not have focus since there might be other windows
- // on top (eg. a dialog window).
- WindowState transferFocusFromWin = win;
- if (mCurrentFocus != null && mCurrentFocus != win
- && mCurrentFocus.mAppToken == win.mAppToken) {
- transferFocusFromWin = mCurrentFocus;
- }
- if (!mInputManager.transferTouchFocus(
- transferFocusFromWin.mInputChannel, mTaskPositioner.mServerChannel)) {
- Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
- mTaskPositioner.unregister();
- mTaskPositioner = null;
- mInputMonitor.updateInputWindowsLw(true /*force*/);
- return false;
- }
-
- mTaskPositioner.startDrag(win, resize, preserveOrientation, startX, startY);
- return true;
- }
-
- private void finishPositioning() {
- if (DEBUG_TASK_POSITIONING) {
- Slog.d(TAG_WM, "finishPositioning");
- }
- synchronized (mWindowMap) {
- if (mTaskPositioner != null) {
- mTaskPositioner.unregister();
- mTaskPositioner = null;
- mInputMonitor.updateInputWindowsLw(true /*force*/);
- }
- }
- }
-
// -------------------------------------------------------------
// Input Events and Focus Management
// -------------------------------------------------------------
@@ -5008,12 +4901,13 @@
}
case TAP_OUTSIDE_TASK: {
- handleTapOutsideTask((DisplayContent)msg.obj, msg.arg1, msg.arg2);
+ mTaskPositioningController.handleTapOutsideTask(
+ (DisplayContent)msg.obj, msg.arg1, msg.arg2);
}
break;
case FINISH_TASK_POSITIONING: {
- finishPositioning();
+ mTaskPositioningController.finishPositioning();
}
break;
@@ -5863,6 +5757,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;
@@ -5987,6 +5882,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 c2ac905..a9708ce 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -19,11 +19,11 @@
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.SurfaceControl.Transaction;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
-import static android.view.SurfaceControl.Transaction;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
@@ -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;
@@ -91,6 +91,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
+import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
@@ -144,6 +145,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;
@@ -159,10 +161,14 @@
import android.view.ViewTreeObserver;
import android.view.WindowInfo;
import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.input.InputWindowHandle;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -185,7 +191,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;
@@ -320,6 +325,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.
@@ -589,6 +599,8 @@
*/
private boolean mDrawnStateEvaluated;
+ private final Point mSurfacePosition = new Point();
+
/**
* Compares two window sub-layers and returns -1 if the first is lesser than the second in terms
* of z-order and 1 otherwise.
@@ -621,7 +633,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;
@@ -772,7 +784,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
@@ -1009,6 +1021,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
@@ -1149,8 +1165,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;
}
/**
@@ -1195,6 +1212,7 @@
|| winAnimator.mSurfaceResized
|| mOutsetsChanged
|| mFrameSizeChanged
+ || mDisplayCutoutChanged
|| configChanged
|| dragResizingChanged
|| !isResizedWhileNotDragResizingReported()
@@ -1214,7 +1232,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
@@ -1458,9 +1477,9 @@
final AppWindowToken atoken = mAppToken;
if (atoken != null) {
return ((!isParentWindowHidden() && !atoken.hiddenRequested)
- || mWinAnimator.mAnimation != null || atoken.mAppAnimator.animation != null);
+ || mWinAnimator.isAnimationSet() || atoken.mAppAnimator.animation != null);
}
- return !isParentWindowHidden() || mWinAnimator.mAnimation != null;
+ return !isParentWindowHidden() || mWinAnimator.isAnimationSet();
}
/**
@@ -1493,7 +1512,7 @@
}
return mHasSurface && mPolicyVisibility && !mDestroying
&& ((!isParentWindowHidden() && mViewVisibility == View.VISIBLE && !mToken.hidden)
- || mWinAnimator.mAnimation != null
+ || mWinAnimator.isAnimationSet()
|| ((mAppToken != null) && (mAppToken.mAppAnimator.animation != null)));
}
@@ -1508,8 +1527,7 @@
// started.
final boolean appAnimationStarting = mAppToken != null
&& mAppToken.mAppAnimator.isAnimationStarting();
- final boolean exitingSelf = mAnimatingExit && (!mWinAnimator.isAnimationStarting()
- && !appAnimationStarting);
+ final boolean exitingSelf = mAnimatingExit && !appAnimationStarting;
final boolean appExiting = mAppToken != null && mAppToken.hidden && !appAnimationStarting;
final boolean exiting = exitingSelf || mDestroying || appExiting;
@@ -1532,7 +1550,7 @@
return isDrawnLw() && mPolicyVisibility
&& ((!isParentWindowHidden() &&
(atoken == null || !atoken.hiddenRequested))
- || mWinAnimator.mAnimating
+ || mWinAnimator.isAnimationSet()
|| (atoken != null && atoken.mAppAnimator.animation != null));
}
@@ -1541,7 +1559,7 @@
*/
@Override
public boolean isAnimatingLw() {
- return mWinAnimator.mAnimation != null
+ return mWinAnimator.isAnimationSet()
|| (mAppToken != null && mAppToken.mAppAnimator.animation != null);
}
@@ -1588,7 +1606,7 @@
// to determine if it's occluding apps.
return ((!mIsWallpaper && mAttrs.format == PixelFormat.OPAQUE)
|| (mIsWallpaper && mWallpaperVisible))
- && isDrawnLw() && mWinAnimator.mAnimation == null
+ && isDrawnLw() && !mWinAnimator.isAnimationSet()
&& (mAppToken == null || mAppToken.mAppAnimator.animation == null);
}
@@ -1720,7 +1738,7 @@
* listeners and optionally animate it. Simply checking a change of position is not enough,
* because being move due to dock divider is not a trigger for animation.
*/
- void handleWindowMovedIfNeeded() {
+ void handleWindowMovedIfNeeded(Transaction t) {
if (!hasMoved()) {
return;
}
@@ -1738,7 +1756,7 @@
&& !isDragResizing() && !adjustedForMinimizedDockOrIme
&& getWindowConfiguration().hasMovementAnimations()
&& !mWinAnimator.mLastHidden) {
- mWinAnimator.setMoveAnimation(left, top);
+ startMoveAnimation(t, left, top);
}
//TODO (multidisplay): Accessibility supported only for the default display.
@@ -2445,10 +2463,10 @@
if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility true: " + this);
if (doAnimation) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility="
- + mPolicyVisibility + " mAnimation=" + mWinAnimator.mAnimation);
+ + mPolicyVisibility + " isAnimationSet=" + mWinAnimator.isAnimationSet());
if (!mToken.okToAnimate()) {
doAnimation = false;
- } else if (mPolicyVisibility && mWinAnimator.mAnimation == null) {
+ } else if (mPolicyVisibility && !mWinAnimator.isAnimationSet()) {
// Check for the case where we are currently visible and
// not animating; we do not want to do animation at such a
// point to become visible when we already are.
@@ -2487,7 +2505,7 @@
}
if (doAnimation) {
mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
- if (mWinAnimator.mAnimation == null) {
+ if (!mWinAnimator.isAnimationSet()) {
doAnimation = false;
}
}
@@ -2587,14 +2605,6 @@
return mAnimatingExit || (mService.mClosingApps.contains(mAppToken));
}
- @Override
- boolean isAnimating() {
- if (mWinAnimator.isAnimationSet() || mAnimatingExit) {
- return true;
- }
- return super.isAnimating();
- }
-
void addWinAnimatorToList(ArrayList<WindowStateAnimator> animators) {
animators.add(mWinAnimator);
@@ -2849,6 +2859,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.
@@ -2858,7 +2869,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.
}
@@ -2866,7 +2877,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.
@@ -2880,6 +2892,7 @@
mStableInsetsChanged = false;
mOutsetsChanged = false;
mFrameSizeChanged = false;
+ mDisplayCutoutChanged = false;
mResizedWhileNotDragResizingReported = true;
mWinAnimator.mSurfaceResized = false;
mReportOrientationChanged = false;
@@ -2922,14 +2935,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;
}
@@ -3116,6 +3131,7 @@
proto.end(token);
}
+ @Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
final TaskStack stack = getStack();
pw.print(prefix); pw.print("mDisplayId="); pw.print(getDisplayId());
@@ -3246,6 +3262,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);
@@ -3254,8 +3271,10 @@
pw.print(" stable="); mLastStableInsets.printShortString(pw);
pw.print(" physical="); mLastOutsets.printShortString(pw);
pw.print(" outset="); mLastOutsets.printShortString(pw);
+ pw.print(" cutout=" + mLastDisplayCutout);
pw.println();
}
+ super.dump(pw, prefix, dumpAll);
pw.print(prefix); pw.print(mWinAnimator); pw.println(":");
mWinAnimator.dump(pw, prefix + " ", dumpAll);
if (mAnimatingExit || mRemoveOnExit || mDestroying || mRemoved) {
@@ -3314,7 +3333,7 @@
@Override
String getName() {
return Integer.toHexString(System.identityHashCode(this))
- + " " + getWindowTag();
+ + " " + getWindowTag();
}
CharSequence getWindowTag() {
@@ -3675,7 +3694,7 @@
+ " tok.hiddenRequested="
+ (mAppToken != null && mAppToken.hiddenRequested)
+ " tok.hidden=" + (mAppToken != null && mAppToken.hidden)
- + " animating=" + mWinAnimator.mAnimating
+ + " animationSet=" + mWinAnimator.isAnimationSet()
+ " tok animating="
+ (mWinAnimator.mAppAnimator != null && mWinAnimator.mAppAnimator.animating)
+ " Callers=" + Debug.getCallers(4));
@@ -3881,23 +3900,10 @@
return null;
}
- boolean isWindowAnimationSet() {
- if (mWinAnimator.isWindowAnimationSet()) {
- return true;
- }
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState c = mChildren.get(i);
- if (c.isWindowAnimationSet()) {
- return true;
- }
- }
- return false;
- }
-
void onExitAnimationDone() {
if (DEBUG_ANIM) Slog.v(TAG, "onExitAnimationDone in " + this
+ ": exiting=" + mAnimatingExit + " remove=" + mRemoveOnExit
- + " windowAnimating=" + mWinAnimator.isWindowAnimationSet());
+ + " selfAnimating=" + isSelfAnimating());
if (!mChildren.isEmpty()) {
// Copying to a different list as multiple children can be removed.
@@ -3921,18 +3927,16 @@
}
}
- if (!mWinAnimator.isWindowAnimationSet()) {
- //TODO (multidisplay): Accessibility is supported only for the default display.
- if (mService.mAccessibilityController != null && getDisplayId() == DEFAULT_DISPLAY) {
- mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
- }
- }
-
- if (!mAnimatingExit) {
+ if (isSelfAnimating()) {
return;
}
- if (mWinAnimator.isWindowAnimationSet()) {
+ //TODO (multidisplay): Accessibility is supported only for the default display.
+ if (mService.mAccessibilityController != null && getDisplayId() == DEFAULT_DISPLAY) {
+ mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+ }
+
+ if (!mAnimatingExit) {
return;
}
@@ -3986,10 +3990,6 @@
mAnimatingExit = false;
didSomething = true;
}
- if (mWinAnimator.mAnimating) {
- mWinAnimator.mAnimating = false;
- didSomething = true;
- }
if (mDestroying) {
mDestroying = false;
mService.mDestroySurface.remove(this);
@@ -4078,7 +4078,7 @@
+ " mDrawState=" + mWinAnimator.mDrawState
+ " ph=" + isParentWindowHidden()
+ " th=" + (mAppToken != null ? mAppToken.hiddenRequested : false)
- + " a=" + mWinAnimator.mAnimating);
+ + " a=" + mWinAnimator.isAnimationSet());
}
}
@@ -4278,6 +4278,36 @@
mLastVisibleInsets.set(mVisibleInsets);
mLastStableInsets.set(mStableInsets);
mLastOutsets.set(mOutsets);
+ mLastDisplayCutout = mDisplayCutout;
+ }
+
+ void startAnimation(Animation anim) {
+ final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
+ anim.initialize(mFrame.width(), mFrame.height(),
+ displayInfo.appWidth, displayInfo.appHeight);
+ anim.restrictDuration(MAX_ANIMATION_DURATION);
+ anim.scaleCurrentDuration(mService.getWindowAnimationScaleLocked());
+ final AnimationAdapter adapter = new LocalAnimationAdapter(
+ new WindowAnimationSpec(anim, mSurfacePosition), mService.mSurfaceAnimationRunner);
+ startAnimation(mPendingTransaction, adapter);
+ commitPendingTransaction();
+ }
+
+ private void startMoveAnimation(Transaction t, int left, int top) {
+ if (DEBUG_ANIM) Slog.v(TAG, "Setting move animation on " + this);
+ final AnimationAdapter adapter = new LocalAnimationAdapter(
+ new MoveAnimationSpec(mLastFrame.left, mLastFrame.top, left, top),
+ mService.mSurfaceAnimationRunner);
+ startAnimation(t, adapter);
+ }
+
+ private void startAnimation(Transaction t, AnimationAdapter adapter) {
+ startAnimation(t, adapter, mWinAnimator.mLastHidden);
+ }
+
+ @Override
+ protected void onAnimationFinished() {
+ mWinAnimator.onAnimationFinished();
}
// TODO: Hack to work around the number of states AppWindowToken needs to access without having
@@ -4331,15 +4361,6 @@
}
}
- boolean usesRelativeZOrdering() {
- if (!isChildWindow()) {
- return false;
- } else if (mAttrs.type == TYPE_APPLICATION_MEDIA_OVERLAY) {
- return true;
- } else {
- return false;
- }
- }
@Override
boolean shouldMagnify() {
@@ -4370,11 +4391,6 @@
return getAnimLayerAdjustment() > 0 || mWillReplaceWindow;
}
- @Override
- SurfaceControl.Builder makeSurface() {
- return getParent().makeChildSurface(this);
- }
-
private void applyDims(Dimmer dimmer) {
if (!mAnimatingExit && mAppDied) {
mIsDimming = true;
@@ -4394,11 +4410,51 @@
applyDims(dimmer);
}
+ updateSurfacePosition(mPendingTransaction);
+
mWinAnimator.prepareSurfaceLocked(true);
super.prepareSurfaces();
}
@Override
+ public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
+ super.onAnimationLeashCreated(t, leash);
+
+ // Leash is now responsible for position, so set our position to 0.
+ t.setPosition(mSurfaceControl, 0, 0);
+ }
+
+ @Override
+ public void onAnimationLeashDestroyed(Transaction t) {
+ super.onAnimationLeashDestroyed(t);
+ updateSurfacePosition(t);
+ }
+
+ void updateSurfacePosition(Transaction t) {
+ if (mSurfaceControl == null) {
+ return;
+ }
+
+ int left = mFrame.left;
+ int top = mFrame.top;
+ if (isChildWindow()) {
+ // TODO: This probably falls apart at some point and we should
+ // actually compute relative coordinates.
+ final WindowState parent = getParentWindow();
+ left -= parent.mFrame.left;
+ top -= parent.mFrame.top;
+ }
+
+ // Expand for surface insets. See WindowState.expandForSurfaceInsets.
+ left -= mAttrs.surfaceInsets.left;
+ top -= mAttrs.surfaceInsets.top;
+ mSurfacePosition.set(left, top);
+ if (!mSurfaceAnimator.hasLeash()) {
+ t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
+ }
+ }
+
+ @Override
void assignLayer(Transaction t, int layer) {
// See comment in assignRelativeLayerForImeTargetChild
if (!isChildWindow()
@@ -4414,4 +4470,58 @@
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++;
+ }
+ }
+
+ private final class MoveAnimationSpec implements AnimationSpec {
+
+ private final long mDuration;
+ private Interpolator mInterpolator;
+ private Point mFrom = new Point();
+ private Point mTo = new Point();
+
+ private MoveAnimationSpec(int fromX, int fromY, int toX, int toY) {
+ final Animation anim = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.window_move_from_decor);
+ mDuration = anim.computeDurationHint();
+ mInterpolator = anim.getInterpolator();
+ mFrom.set(fromX, fromY);
+ mTo.set(toX, toY);
+ }
+
+ @Override
+ public long getDuration() {
+ return mDuration;
+ }
+
+ @Override
+ public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
+ final float fraction = (float) currentPlayTime / getDuration();
+ final float v = mInterpolator.getInterpolation(fraction);
+ t.setPosition(leash, mFrom.x + (mTo.x - mFrom.x) * v,
+ mFrom.y + (mTo.y - mFrom.y) * v);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 4b5661f..0eabc89 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -23,16 +23,16 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.AppWindowAnimator.sDummyAnimation;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
@@ -40,7 +40,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
-import static com.android.server.wm.WindowManagerService.localLOGV;
import static com.android.server.wm.WindowManagerService.logWithStack;
import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
@@ -65,14 +64,13 @@
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
import com.android.server.policy.WindowManagerPolicy;
-import java.io.PrintWriter;
import java.io.FileDescriptor;
+import java.io.PrintWriter;
/**
* Keep track of animations and surface operations for a single WindowState.
@@ -112,20 +110,9 @@
final boolean mIsWallpaper;
private final WallpaperController mWallpaperControllerLocked;
- // Currently running animation.
- boolean mAnimating;
- boolean mLocalAnimating;
- Animation mAnimation;
boolean mAnimationIsEntrance;
- boolean mHasTransformation;
- boolean mHasLocalTransformation;
- final Transformation mTransformation = new Transformation();
- boolean mWasAnimating; // Were we animating going into the most recent animation step?
int mAnimLayer;
int mLastLayer;
- long mAnimationStartTime;
- long mLastAnimationTime;
- int mStackClip = STACK_CLIP_BEFORE_ANIM;
/**
* Set when we have changed the size of the surface, to know that
@@ -168,13 +155,6 @@
private final Rect mSystemDecorRect = new Rect();
private final Rect mLastSystemDecorRect = new Rect();
- // Used to save animation distances between the time they are calculated and when they are used.
- private int mAnimDx;
- private int mAnimDy;
-
- /** Is the next animation to be started a window move animation? */
- private boolean mAnimateMove = false;
-
float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
private float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
@@ -226,8 +206,6 @@
int mAttrType;
- static final long PENDING_TRANSACTION_FINISH_WAIT_TIME = 100;
-
boolean mForceScaleUntilResize;
// WindowState.mHScale and WindowState.mVScale contain the
@@ -247,15 +225,6 @@
mAnimator = service.mAnimator;
mPolicy = service.mPolicy;
mContext = service.mContext;
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent != null) {
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- mAnimDx = displayInfo.appWidth;
- mAnimDy = displayInfo.appHeight;
- } else {
- Slog.w(TAG, "WindowStateAnimator ctor: Display has been removed");
- // This is checked on return and dealt with.
- }
mWin = win;
mParentWinAnimator = !win.isChildWindow() ? null : win.getParentWindow().mWinAnimator;
@@ -266,54 +235,11 @@
mWallpaperControllerLocked = mService.mRoot.mWallpaperController;
}
- public void setAnimation(Animation anim, long startTime, int stackClip) {
- if (localLOGV) Slog.v(TAG, "Setting animation in " + this + ": " + anim);
- mAnimating = false;
- mLocalAnimating = false;
- mAnimation = anim;
- mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
- mAnimation.scaleCurrentDuration(mService.getWindowAnimationScaleLocked());
- // Start out animation gone if window is gone, or visible if window is visible.
- mTransformation.clear();
- mTransformation.setAlpha(mLastHidden ? 0 : 1);
- mHasLocalTransformation = true;
- mAnimationStartTime = startTime;
- mStackClip = stackClip;
- }
-
- public void setAnimation(Animation anim, int stackClip) {
- setAnimation(anim, -1, stackClip);
- }
-
- public void setAnimation(Animation anim) {
- setAnimation(anim, -1, STACK_CLIP_AFTER_ANIM);
- }
-
- public void clearAnimation() {
- if (mAnimation != null) {
- mAnimating = true;
- mLocalAnimating = false;
- mAnimation.cancel();
- mAnimation = null;
- mStackClip = STACK_CLIP_BEFORE_ANIM;
- }
- }
-
/**
* Is the window or its container currently set to animate or currently animating?
*/
boolean isAnimationSet() {
- return mAnimation != null
- || (mParentWinAnimator != null && mParentWinAnimator.mAnimation != null)
- || (mAppAnimator != null && mAppAnimator.isAnimating());
- }
-
- /**
- * @return whether an animation is about to start, i.e. the animation is set already but we
- * haven't processed the first frame yet.
- */
- boolean isAnimationStarting() {
- return isAnimationSet() && !mAnimating;
+ return mWin.isAnimating();
}
/** Is the window animating the DummyAnimation? */
@@ -323,13 +249,6 @@
}
/**
- * Is this window currently set to animate or currently animating?
- */
- boolean isWindowAnimationSet() {
- return mAnimation != null;
- }
-
- /**
* Is this window currently waiting to run an opening animation?
*/
boolean isWaitingForOpening() {
@@ -341,130 +260,23 @@
if (DEBUG_ANIM) Slog.d(TAG,
"cancelExitAnimationForNextAnimationLocked: " + mWin);
- if (mAnimation != null) {
- mAnimation.cancel();
- mAnimation = null;
- mLocalAnimating = false;
- mWin.destroySurfaceUnchecked();
- }
+ mWin.cancelAnimation();
+ mWin.destroySurfaceUnchecked();
}
- private boolean stepAnimation(long currentTime) {
- if ((mAnimation == null) || !mLocalAnimating) {
- return false;
- }
- currentTime = getAnimationFrameTime(mAnimation, currentTime);
- mTransformation.clear();
- final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
- if (mAnimationStartDelayed && mAnimationIsEntrance) {
- mTransformation.setAlpha(0f);
- }
- if (false && DEBUG_ANIM) Slog.v(TAG, "Stepped animation in " + this + ": more=" + more
- + ", xform=" + mTransformation);
- return more;
- }
-
- // This must be called while inside a transaction. Returns true if
- // there is more animation to run.
- boolean stepAnimationLocked(long currentTime) {
- // Save the animation state as it was before this step so WindowManagerService can tell if
- // we just started or just stopped animating by comparing mWasAnimating with isAnimationSet().
- mWasAnimating = mAnimating;
- final DisplayContent displayContent = mWin.getDisplayContent();
- if (mWin.mToken.okToAnimate()) {
- // We will run animations as long as the display isn't frozen.
-
- if (mWin.isDrawnLw() && mAnimation != null) {
- mHasTransformation = true;
- mHasLocalTransformation = true;
- if (!mLocalAnimating) {
- if (DEBUG_ANIM) Slog.v(
- TAG, "Starting animation in " + this +
- " @ " + currentTime + ": ww=" + mWin.mFrame.width() +
- " wh=" + mWin.mFrame.height() +
- " dx=" + mAnimDx + " dy=" + mAnimDy +
- " scale=" + mService.getWindowAnimationScaleLocked());
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- if (mAnimateMove) {
- mAnimateMove = false;
- mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
- mAnimDx, mAnimDy);
- } else {
- mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
- displayInfo.appWidth, displayInfo.appHeight);
- }
- mAnimDx = displayInfo.appWidth;
- mAnimDy = displayInfo.appHeight;
- mAnimation.setStartTime(mAnimationStartTime != -1
- ? mAnimationStartTime
- : currentTime);
- mLocalAnimating = true;
- mAnimating = true;
- }
- if ((mAnimation != null) && mLocalAnimating) {
- mLastAnimationTime = currentTime;
- if (stepAnimation(currentTime)) {
- return true;
- }
- }
- if (DEBUG_ANIM) Slog.v(
- TAG, "Finished animation in " + this +
- " @ " + currentTime);
- //WindowManagerService.this.dump();
- }
- mHasLocalTransformation = false;
- if ((!mLocalAnimating || mAnimationIsEntrance) && mAppAnimator != null
- && mAppAnimator.animation != null) {
- // When our app token is animating, we kind-of pretend like
- // we are as well. Note the mLocalAnimating mAnimationIsEntrance
- // part of this check means that we will only do this if
- // our window is not currently exiting, or it is not
- // locally animating itself. The idea being that one that
- // is exiting and doing a local animation should be removed
- // once that animation is done.
- mAnimating = true;
- mHasTransformation = true;
- mTransformation.clear();
- return false;
- } else if (mHasTransformation) {
- // Little trick to get through the path below to act like
- // we have finished an animation.
- mAnimating = true;
- } else if (isAnimationSet()) {
- mAnimating = true;
- }
- } else if (mAnimation != null) {
- // If the display is frozen, and there is a pending animation,
- // clear it and make sure we run the cleanup code.
- mAnimating = true;
- }
-
- if (!mAnimating && !mLocalAnimating) {
- return false;
- }
-
+ void onAnimationFinished() {
// Done animating, clean up.
if (DEBUG_ANIM) Slog.v(
- TAG, "Animation done in " + this + ": exiting=" + mWin.mAnimatingExit
- + ", reportedVisible="
- + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
+ TAG, "Animation done in " + this + ": exiting=" + mWin.mAnimatingExit
+ + ", reportedVisible="
+ + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
- mAnimating = false;
- mLocalAnimating = false;
- if (mAnimation != null) {
- mAnimation.cancel();
- mAnimation = null;
- }
if (mAnimator.mWindowDetachedWallpaper == mWin) {
mAnimator.mWindowDetachedWallpaper = null;
}
- mAnimLayer = mWin.getSpecialWindowAnimLayerAdjustment();
- if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this + " anim layer: " + mAnimLayer);
- mHasTransformation = false;
- mHasLocalTransformation = false;
- mStackClip = STACK_CLIP_BEFORE_ANIM;
+
mWin.checkPolicyVisibilityChange();
- mTransformation.clear();
+ final DisplayContent displayContent = mWin.getDisplayContent();
if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.mPolicyVisibility) {
// Upon completion of a not-visible to visible status bar animation a relayout is
// required.
@@ -475,7 +287,11 @@
mWin.onExitAnimationDone();
final int displayId = mWin.getDisplayId();
- mAnimator.setPendingLayoutChanges(displayId, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
+ int pendingLayoutChanges = FINISH_LAYOUT_REDO_ANIM;
+ if (displayContent.mWallpaperController.isWallpaperTarget(mWin)) {
+ pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ }
+ mAnimator.setPendingLayoutChanges(displayId, pendingLayoutChanges);
if (DEBUG_LAYOUT_REPEATS)
mService.mWindowPlacerLocked.debugLayoutRepeats(
"WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId));
@@ -483,8 +299,6 @@
if (mWin.mAppToken != null) {
mWin.mAppToken.updateReportedVisibilityLocked();
}
-
- return false;
}
void hide(String reason) {
@@ -602,13 +416,6 @@
return mWin.getDisplayContent().getDisplay().getLayerStack();
}
- void updateLayerStackInTransaction() {
- if (mSurfaceController != null) {
- mSurfaceController.setLayerStackInTransaction(
- getLayerStack());
- }
- }
-
void resetDrawState() {
mDrawState = DRAW_PENDING;
@@ -690,8 +497,8 @@
}
mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
- attrs.getTitle().toString(),
- width, height, format, flags, this, windowType, ownerUid);
+ attrs.getTitle().toString(), width, height, format, flags, this,
+ windowType, ownerUid);
mSurfaceFormat = format;
w.setHasSurface(true);
@@ -727,16 +534,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);
@@ -870,35 +667,8 @@
}
void computeShownFrameLocked() {
- final boolean selfTransformation = mHasLocalTransformation;
Transformation appTransformation = (mAppAnimator != null && mAppAnimator.hasTransformation)
? mAppAnimator.transformation : null;
- Transformation wallpaperTargetTransformation = null;
-
- // Wallpapers are animated based on the "real" window they
- // are currently targeting.
- final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
- if (mIsWallpaper && wallpaperTarget != null && mService.mAnimateWallpaperWithTarget) {
- final WindowStateAnimator wallpaperAnimator = wallpaperTarget.mWinAnimator;
- if (wallpaperAnimator.mHasLocalTransformation &&
- wallpaperAnimator.mAnimation != null &&
- !wallpaperAnimator.mAnimation.getDetachWallpaper()) {
- wallpaperTargetTransformation = wallpaperAnimator.mTransformation;
- if (DEBUG_WALLPAPER && wallpaperTargetTransformation != null) {
- Slog.v(TAG, "WP target attached xform: " + wallpaperTargetTransformation);
- }
- }
- final AppWindowAnimator wpAppAnimator = wallpaperTarget.mAppToken == null ?
- null : wallpaperTarget.mAppToken.mAppAnimator;
- if (wpAppAnimator != null && wpAppAnimator.hasTransformation
- && wpAppAnimator.animation != null
- && !wpAppAnimator.animation.getDetachWallpaper()) {
- appTransformation = wpAppAnimator.transformation;
- if (DEBUG_WALLPAPER && appTransformation != null) {
- Slog.v(TAG, "WP target app xform: " + appTransformation);
- }
- }
- }
final int displayId = mWin.getDisplayId();
final ScreenRotationAnimation screenRotationAnimation =
@@ -907,8 +677,7 @@
screenRotationAnimation != null && screenRotationAnimation.isAnimating();
mHasClipRect = false;
- if (selfTransformation || wallpaperTargetTransformation != null
- || appTransformation != null || screenAnimation) {
+ if (appTransformation != null || screenAnimation) {
// cache often used attributes locally
final Rect frame = mWin.mFrame;
final float tmpFloats[] = mService.mTmpFloats;
@@ -934,34 +703,16 @@
tmpMatrix.reset();
}
tmpMatrix.postScale(mWin.mGlobalScale, mWin.mGlobalScale);
- if (selfTransformation) {
- tmpMatrix.postConcat(mTransformation.getMatrix());
- }
- if (wallpaperTargetTransformation != null) {
- tmpMatrix.postConcat(wallpaperTargetTransformation.getMatrix());
- }
+ // WindowState.prepareSurfaces expands for surface insets (in order they don't get
+ // clipped by the WindowState surface), so we need to go into the other direction here.
+ tmpMatrix.postTranslate(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left,
+ mWin.mYOffset + mWin.mAttrs.surfaceInsets.top);
+
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(left + mWin.mXOffset, top + mWin.mYOffset);
- if (screenAnimation) {
- tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
- }
-
// "convert" it into SurfaceFlinger's format
// (a 2x2 matrix + an offset)
// Here we must not transform the position of the surface
@@ -989,12 +740,6 @@
|| (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)
&& x == frame.left && y == frame.top))) {
//Slog.i(TAG_WM, "Applying alpha transform");
- if (selfTransformation) {
- mShownAlpha *= mTransformation.getAlpha();
- }
- if (wallpaperTargetTransformation != null) {
- mShownAlpha *= wallpaperTargetTransformation.getAlpha();
- }
if (appTransformation != null) {
mShownAlpha *= appTransformation.getAlpha();
if (appTransformation.hasClipRect()) {
@@ -1023,9 +768,6 @@
if ((DEBUG_ANIM || WindowManagerService.localLOGV)
&& (mShownAlpha == 1.0 || mShownAlpha == 0.0)) Slog.v(
TAG, "computeShownFrameLocked: Animating " + this + " mAlpha=" + mAlpha
- + " self=" + (selfTransformation ? mTransformation.getAlpha() : "null")
- + " attached=" + (wallpaperTargetTransformation == null ?
- "null" : wallpaperTargetTransformation.getAlpha())
+ " app=" + (appTransformation == null ? "null" : appTransformation.getAlpha())
+ " screen=" + (screenAnimation ?
screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));
@@ -1045,10 +787,10 @@
TAG, "computeShownFrameLocked: " + this +
" not attached, mAlpha=" + mAlpha);
- mWin.mShownPosition.set(mWin.mFrame.left, mWin.mFrame.top);
- if (mWin.mXOffset != 0 || mWin.mYOffset != 0) {
- mWin.mShownPosition.offset(mWin.mXOffset, mWin.mYOffset);
- }
+ // WindowState.prepareSurfaces expands for surface insets (in order they don't get
+ // clipped by the WindowState surface), so we need to go into the other direction here.
+ mWin.mShownPosition.set(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left,
+ mWin.mYOffset + mWin.mAttrs.surfaceInsets.top);
mShownAlpha = mAlpha;
mHaveMatrix = false;
mDsDx = mWin.mGlobalScale;
@@ -1199,7 +941,7 @@
if (mAppAnimator != null && mAppAnimator.animation != null) {
return mAppAnimator.getStackClip();
} else {
- return mStackClip;
+ return STACK_CLIP_AFTER_ANIM;
}
}
@@ -1451,7 +1193,7 @@
if (mSurfaceResized) {
mReportSurfaceResized = true;
mAnimator.setPendingLayoutChanges(w.getDisplayId(),
- WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
+ FINISH_LAYOUT_REDO_WALLPAPER);
}
}
@@ -1563,7 +1305,7 @@
// Run another pass through performLayout to set mHasContent in the
// LogicalDisplay.
mAnimator.setPendingLayoutChanges(w.getDisplayId(),
- WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
+ FINISH_LAYOUT_REDO_ANIM);
} else {
w.setOrientationChanging(false);
}
@@ -1737,12 +1479,18 @@
* @return true if an animation has been loaded.
*/
boolean applyAnimationLocked(int transit, boolean isEntrance) {
- if (mLocalAnimating && mAnimationIsEntrance == isEntrance) {
+ if (mWin.isSelfAnimating() && mAnimationIsEntrance == isEntrance) {
// If we are trying to apply an animation, but already running
// an animation of the same type, then just leave that one alone.
return true;
}
+ if (isEntrance && mWin.mAttrs.type == TYPE_INPUT_METHOD) {
+ mWin.getDisplayContent().adjustForImeIfNeeded();
+ mWin.setDisplayLayoutNeeded();
+ mService.mWindowPlacerLocked.requestTraversal();
+ }
+
// Only apply an animation if the display isn't frozen. If it is
// frozen, there is no reason to animate and it can cause strange
// artifacts when we unfreeze the display if some different animation
@@ -1781,44 +1529,19 @@
+ " isEntrance=" + isEntrance + " Callers " + Debug.getCallers(3));
if (a != null) {
if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
- setAnimation(a);
+ mWin.startAnimation(a);
mAnimationIsEntrance = isEntrance;
}
} else {
- clearAnimation();
+ mWin.cancelAnimation();
}
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
- if (mWin.mAttrs.type == TYPE_INPUT_METHOD) {
+ if (!isEntrance && mWin.mAttrs.type == TYPE_INPUT_METHOD) {
mWin.getDisplayContent().adjustForImeIfNeeded();
- if (isEntrance) {
- mWin.setDisplayLayoutNeeded();
- mService.mWindowPlacerLocked.requestTraversal();
- }
}
- return mAnimation != null;
- }
- private void applyFadeoutDuringKeyguardExitAnimation() {
- long startTime = mAnimation.getStartTime();
- long duration = mAnimation.getDuration();
- long elapsed = mLastAnimationTime - startTime;
- long fadeDuration = duration - elapsed;
- if (fadeDuration <= 0) {
- // Never mind, this would be no visible animation, so abort the animation change.
- return;
- }
- AnimationSet newAnimation = new AnimationSet(false /* shareInterpolator */);
- newAnimation.setDuration(duration);
- newAnimation.setStartTime(startTime);
- newAnimation.addAnimation(mAnimation);
- Animation fadeOut = AnimationUtils.loadAnimation(
- mContext, com.android.internal.R.anim.app_starting_exit);
- fadeOut.setDuration(fadeDuration);
- fadeOut.setStartOffset(elapsed);
- newAnimation.addAnimation(fadeOut);
- newAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), mAnimDx, mAnimDy);
- mAnimation = newAnimation;
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ return isAnimationSet();
}
void writeToProto(ProtoOutputStream proto, long fieldId) {
@@ -1831,20 +1554,8 @@
}
public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
- if (mAnimating || mLocalAnimating || mAnimationIsEntrance
- || mAnimation != null) {
- pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
- pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
- pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
- pw.print(" mAnimation="); pw.print(mAnimation);
- pw.print(" mStackClip="); pw.println(mStackClip);
- }
- if (mHasTransformation || mHasLocalTransformation) {
- pw.print(prefix); pw.print("XForm: has=");
- pw.print(mHasTransformation);
- pw.print(" hasLocal="); pw.print(mHasLocalTransformation);
- pw.print(" "); mTransformation.printShortString(pw);
- pw.println();
+ if (mAnimationIsEntrance) {
+ pw.print(prefix); pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
}
if (mSurfaceController != null) {
mSurfaceController.dump(pw, prefix, dumpAll);
@@ -1924,44 +1635,6 @@
}
}
- void setMoveAnimation(int left, int top) {
- final Animation a = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.window_move_from_decor);
- setAnimation(a);
- mAnimDx = mWin.mLastFrame.left - left;
- mAnimDy = mWin.mLastFrame.top - top;
- mAnimateMove = true;
- }
-
- void deferTransactionUntilParentFrame(long frameNumber) {
- if (!mWin.isChildWindow()) {
- return;
- }
- mSurfaceController.deferTransactionUntil(
- mWin.getParentWindow().mWinAnimator.mSurfaceController.getHandle(), frameNumber);
- }
-
- /**
- * Sometimes we need to synchronize the first frame of animation with some external event.
- * To achieve this, we prolong the start of the animation and keep producing the first frame of
- * the animation.
- */
- private long getAnimationFrameTime(Animation animation, long currentTime) {
- if (mAnimationStartDelayed) {
- animation.setStartTime(currentTime);
- return currentTime + 1;
- }
- return currentTime;
- }
-
- void startDelayingAnimationStart() {
- mAnimationStartDelayed = true;
- }
-
- void endDelayingAnimationStart() {
- mAnimationStartDelayed = false;
- }
-
void seamlesslyRotateWindow(int oldRotation, int newRotation) {
final WindowState w = mWin;
if (!w.isVisibleNow() || w.mIsWallpaper) {
@@ -2043,4 +1716,8 @@
mSurfaceController.detachChildren();
}
}
+
+ int getLayer() {
+ return mLastLayer;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 6746754..e26a362 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -59,8 +59,8 @@
private boolean mSurfaceShown = false;
private float mSurfaceX = 0;
private float mSurfaceY = 0;
- private float mSurfaceW = 0;
- private float mSurfaceH = 0;
+ private int mSurfaceW = 0;
+ private int mSurfaceH = 0;
// Initialize to the identity matrix.
private float mLastDsdx = 1;
@@ -517,11 +517,11 @@
return mSurfaceY;
}
- float getWidth() {
+ int getWidth() {
return mSurfaceW;
}
- float getHeight() {
+ int getHeight() {
return mSurfaceH;
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 169d0a3..d8e7457 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -462,6 +462,7 @@
appAnimator.setNullAnimation();
// TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
// animating?
+ wtoken.setAllAppWinAnimators();
wtoken.setVisibility(animLp, false, transit, false, voiceInteraction);
wtoken.updateReportedVisibilityLocked();
// setAllAppWinAnimators so the windows get onExitAnimationDone once the animation is
@@ -606,7 +607,7 @@
+ ", oldWallpaper=" + oldWallpaper
+ ", openingApps=" + openingApps
+ ", closingApps=" + closingApps);
- mService.mAnimateWallpaperWithTarget = false;
+
if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
@@ -645,8 +646,6 @@
transit = TRANSIT_WALLPAPER_OPEN;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
+ AppTransition.appTransitionToString(transit));
- } else {
- mService.mAnimateWallpaperWithTarget = true;
}
}
return transit;
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..e53aa81
--- /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-1x-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/BroadcastRadio/BroadcastRadioService.cpp b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
index e1dbdeb..222ac5b 100644
--- a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
+++ b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
@@ -25,7 +25,7 @@
#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
#include <android/hardware/broadcastradio/1.2/IBroadcastRadioFactory.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
-#include <broadcastradio-utils/Utils.h>
+#include <broadcastradio-utils-1x/Utils.h>
#include <core_jni_helpers.h>
#include <hidl/ServiceManagement.h>
#include <nativehelper/JNIHelp.h>
diff --git a/services/core/jni/BroadcastRadio/Tuner.cpp b/services/core/jni/BroadcastRadio/Tuner.cpp
index df53fee..63339e9 100644
--- a/services/core/jni/BroadcastRadio/Tuner.cpp
+++ b/services/core/jni/BroadcastRadio/Tuner.cpp
@@ -24,7 +24,7 @@
#include <android/hardware/broadcastradio/1.2/IBroadcastRadioFactory.h>
#include <binder/IPCThreadState.h>
-#include <broadcastradio-utils/Utils.h>
+#include <broadcastradio-utils-1x/Utils.h>
#include <core_jni_helpers.h>
#include <media/AudioSystem.h>
#include <nativehelper/JNIHelp.h>
diff --git a/services/core/jni/BroadcastRadio/TunerCallback.cpp b/services/core/jni/BroadcastRadio/TunerCallback.cpp
index d624df6..d0ba005 100644
--- a/services/core/jni/BroadcastRadio/TunerCallback.cpp
+++ b/services/core/jni/BroadcastRadio/TunerCallback.cpp
@@ -22,7 +22,7 @@
#include "Tuner.h"
#include "convert.h"
-#include <broadcastradio-utils/Utils.h>
+#include <broadcastradio-utils-1x/Utils.h>
#include <core_jni_helpers.h>
#include <nativehelper/JNIHelp.h>
#include <utils/Log.h>
diff --git a/services/core/jni/BroadcastRadio/convert.cpp b/services/core/jni/BroadcastRadio/convert.cpp
index 734ce79..f5381a8 100644
--- a/services/core/jni/BroadcastRadio/convert.cpp
+++ b/services/core/jni/BroadcastRadio/convert.cpp
@@ -21,7 +21,7 @@
#include "regions.h"
-#include <broadcastradio-utils/Utils.h>
+#include <broadcastradio-utils-1x/Utils.h>
#include <core_jni_helpers.h>
#include <nativehelper/JNIHelp.h>
#include <utils/Log.h>
diff --git a/services/core/jni/BroadcastRadio/regions.cpp b/services/core/jni/BroadcastRadio/regions.cpp
index b7fd0f3..1757a4d 100644
--- a/services/core/jni/BroadcastRadio/regions.cpp
+++ b/services/core/jni/BroadcastRadio/regions.cpp
@@ -19,7 +19,7 @@
#include "regions.h"
-#include <broadcastradio-utils/Utils.h>
+#include <broadcastradio-utils-1x/Utils.h>
#include <utils/Log.h>
namespace android {
diff --git a/services/core/jni/com_android_server_GraphicsStatsService.cpp b/services/core/jni/com_android_server_GraphicsStatsService.cpp
index 8385020..d1d253b 100644
--- a/services/core/jni/com_android_server_GraphicsStatsService.cpp
+++ b/services/core/jni/com_android_server_GraphicsStatsService.cpp
@@ -39,7 +39,7 @@
}
static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jstring jpackage,
- jint versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
+ jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
std::string path;
const ProfileData* data = nullptr;
LOG_ALWAYS_FATAL_IF(jdata == nullptr && jpath == nullptr, "Path and data can't both be null");
@@ -78,7 +78,7 @@
}
static void saveBuffer(JNIEnv* env, jobject clazz, jstring jpath, jstring jpackage,
- jint versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
+ jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
ScopedByteArrayRO buffer(env, jdata);
LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
"Buffer size %zu doesn't match expected %zu!", buffer.size(), sizeof(ProfileData));
@@ -96,10 +96,10 @@
static const JNINativeMethod sMethods[] = {
{ "nGetAshmemSize", "()I", (void*) getAshmemSize },
{ "nCreateDump", "(IZ)J", (void*) createDump },
- { "nAddToDump", "(JLjava/lang/String;Ljava/lang/String;IJJ[B)V", (void*) addToDump },
+ { "nAddToDump", "(JLjava/lang/String;Ljava/lang/String;JJJ[B)V", (void*) addToDump },
{ "nAddToDump", "(JLjava/lang/String;)V", (void*) addFileToDump },
{ "nFinishDump", "(J)V", (void*) finishDump },
- { "nSaveBuffer", "(Ljava/lang/String;Ljava/lang/String;IJJ[B)V", (void*) saveBuffer },
+ { "nSaveBuffer", "(Ljava/lang/String;Ljava/lang/String;JJJ[B)V", (void*) saveBuffer },
};
int register_android_server_GraphicsStatsService(JNIEnv* env)
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..246bd42 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -19,7 +19,10 @@
#define LOG_NDEBUG 0
#include <android/hardware/gnss/1.0/IGnss.h>
+#include <android/hardware/gnss/1.1/IGnss.h>
+#include <android/hardware/gnss/1.0/IGnssMeasurement.h>
+#include <android/hardware/gnss/1.1/IGnssMeasurement.h>
#include <nativehelper/JNIHelp.h>
#include "jni.h"
#include "hardware_legacy/power.h"
@@ -77,21 +80,23 @@
using android::hardware::hidl_vec;
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 IGnss_V1_1 = android::hardware::gnss::V1_1::IGnss;
+using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
+using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
+using android::hardware::gnss::V1_0::IGnss;
using android::hardware::gnss::V1_0::IAGnss;
using android::hardware::gnss::V1_0::IAGnssCallback;
using android::hardware::gnss::V1_0::IAGnssCallback;
using android::hardware::gnss::V1_0::IAGnssRil;
using android::hardware::gnss::V1_0::IAGnssRilCallback;
-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;
using android::hardware::gnss::V1_0::IGnssGeofencing;
-using android::hardware::gnss::V1_0::IGnssMeasurement;
using android::hardware::gnss::V1_0::IGnssMeasurementCallback;
using android::hardware::gnss::V1_0::IGnssNavigationMessage;
using android::hardware::gnss::V1_0::IGnssNavigationMessageCallback;
@@ -99,12 +104,13 @@
using android::hardware::gnss::V1_0::IGnssNiCallback;
using android::hardware::gnss::V1_0::IGnssXtra;
using android::hardware::gnss::V1_0::IGnssXtraCallback;
+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 +119,7 @@
sp<GnssDeathRecipient> gnssHalDeathRecipient = nullptr;
sp<IGnss> gnssHal = nullptr;
+sp<IGnss_V1_1> gnssHal_V1_1 = nullptr;
sp<IGnssXtra> gnssXtraIface = nullptr;
sp<IAGnssRil> agnssRilIface = nullptr;
sp<IGnssGeofencing> gnssGeofencingIface = nullptr;
@@ -121,7 +128,8 @@
sp<IGnssDebug> gnssDebugIface = nullptr;
sp<IGnssConfiguration> gnssConfigurationIface = nullptr;
sp<IGnssNi> gnssNiIface = nullptr;
-sp<IGnssMeasurement> gnssMeasurementIface = nullptr;
+sp<IGnssMeasurement_V1_0> gnssMeasurementIface = nullptr;
+sp<IGnssMeasurement_V1_1> gnssMeasurementIface_V1_1 = nullptr;
sp<IGnssNavigationMessage> gnssNavigationMessageIface = nullptr;
#define WAKE_LOCK_NAME "GPS"
@@ -303,33 +311,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 +349,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 +359,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 +370,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 +505,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 +523,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 +543,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 +997,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(),
@@ -1050,7 +1071,14 @@
}
// TODO(b/31632518)
- gnssHal = IGnss::getService();
+ gnssHal_V1_1 = IGnss_V1_1::getService();
+ if (gnssHal_V1_1 == nullptr) {
+ ALOGD("gnssHal 1.1 was null, trying 1.0");
+ gnssHal = IGnss::getService();
+ } else {
+ gnssHal = gnssHal_V1_1;
+ }
+
if (gnssHal != nullptr) {
gnssHalDeathRecipient = new GnssDeathRecipient();
hardware::Return<bool> linked = gnssHal->linkToDeath(
@@ -1092,11 +1120,21 @@
gnssNavigationMessageIface = gnssNavigationMessage;
}
- auto gnssMeasurement = gnssHal->getExtensionGnssMeasurement();
- if (!gnssMeasurement.isOk()) {
- ALOGD("Unable to get a handle to GnssMeasurement");
+ if (gnssHal_V1_1 != nullptr) {
+ auto gnssMeasurement = gnssHal_V1_1->getExtensionGnssMeasurement_1_1();
+ if (!gnssMeasurement.isOk()) {
+ ALOGD("Unable to get a handle to GnssMeasurement");
+ } else {
+ gnssMeasurementIface_V1_1 = gnssMeasurement;
+ gnssMeasurementIface = gnssMeasurementIface_V1_1;
+ }
} else {
- gnssMeasurementIface = gnssMeasurement;
+ auto gnssMeasurement_V1_0 = gnssHal->getExtensionGnssMeasurement();
+ if (!gnssMeasurement_V1_0.isOk()) {
+ ALOGD("Unable to get a handle to GnssMeasurement");
+ } else {
+ gnssMeasurementIface = gnssMeasurement_V1_0;
+ }
}
auto gnssDebug = gnssHal->getExtensionGnssDebug();
@@ -1160,7 +1198,6 @@
if (!mCallbacksObj)
mCallbacksObj = env->NewGlobalRef(obj);
- sp<IGnssCallback> gnssCbIface = new GnssCallback();
/*
* Fail if the main interface fails to initialize
*/
@@ -1169,7 +1206,14 @@
return JNI_FALSE;
}
- auto result = gnssHal->setCallback(gnssCbIface);
+ sp<IGnssCallback> gnssCbIface = new GnssCallback();
+
+ Return<bool> result = false;
+ if (gnssHal_V1_1 != nullptr) {
+ result = gnssHal_V1_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 +1226,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 +1234,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();
@@ -1225,21 +1269,27 @@
static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */,
jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy,
- jint preferred_time) {
- if (gnssHal != nullptr) {
- auto result = gnssHal->setPositionMode(static_cast<IGnss::GnssPositionMode>(mode),
- static_cast<IGnss::GnssPositionRecurrence>(recurrence),
- min_interval,
- preferred_accuracy,
- preferred_time);
- if (!result.isOk()) {
- ALOGE("%s: GNSS setPositionMode failed\n", __func__);
- return JNI_FALSE;
- } else {
- return result;
- }
+ jint preferred_time, jboolean low_power_mode) {
+ Return<bool> result = false;
+ if (gnssHal_V1_1 != nullptr) {
+ result = gnssHal_V1_1->setPositionMode_1_1(static_cast<IGnss::GnssPositionMode>(mode),
+ static_cast<IGnss::GnssPositionRecurrence>(recurrence),
+ min_interval,
+ preferred_accuracy,
+ preferred_time,
+ low_power_mode);
+ } else if (gnssHal != nullptr) {
+ result = gnssHal->setPositionMode(static_cast<IGnss::GnssPositionMode>(mode),
+ static_cast<IGnss::GnssPositionRecurrence>(recurrence),
+ min_interval,
+ preferred_accuracy,
+ preferred_time);
+ }
+ if (!result.isOk()) {
+ ALOGE("%s: GNSS setPositionMode failed\n", __func__);
+ return JNI_FALSE;
} else {
- return JNI_FALSE;
+ return result;
}
}
@@ -1649,16 +1699,29 @@
}
static jboolean android_location_GnssLocationProvider_start_measurement_collection(
- JNIEnv* env,
- jobject obj) {
+ JNIEnv* /* env */,
+ jobject /* obj */,
+ jboolean enableFullTracking) {
if (gnssMeasurementIface == nullptr) {
ALOGE("GNSS Measurement interface is not available.");
return JNI_FALSE;
}
sp<GnssMeasurementCallback> cbIface = new GnssMeasurementCallback();
- IGnssMeasurement::GnssMeasurementStatus result = gnssMeasurementIface->setCallback(cbIface);
- if (result != IGnssMeasurement::GnssMeasurementStatus::SUCCESS) {
+ IGnssMeasurement_V1_0::GnssMeasurementStatus result =
+ IGnssMeasurement_V1_0::GnssMeasurementStatus::ERROR_GENERIC;;
+ if (gnssMeasurementIface_V1_1 != nullptr) {
+ result = gnssMeasurementIface_V1_1->setCallback_1_1(cbIface,
+ enableFullTracking);
+ } else {
+ if (enableFullTracking == JNI_TRUE) {
+ // full tracking mode not supported in 1.0 HAL
+ return JNI_FALSE;
+ }
+ result = gnssMeasurementIface->setCallback(cbIface);
+ }
+
+ if (result != IGnssMeasurement_V1_0::GnssMeasurementStatus::SUCCESS) {
ALOGE("An error has been found on GnssMeasurementInterface::init, status=%d",
static_cast<int32_t>(result));
return JNI_FALSE;
@@ -1911,8 +1974,8 @@
{"native_cleanup", "()V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_cleanup)},
{"native_set_position_mode",
- "(IIIII)Z",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_set_position_mode)},
+ "(IIIIIZ)Z",
+ reinterpret_cast<void*>(android_location_GnssLocationProvider_set_position_mode)},
{"native_start", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_start)},
{"native_stop", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_stop)},
{"native_delete_aiding_data",
@@ -1980,7 +2043,7 @@
reinterpret_cast<void *>(
android_location_GnssLocationProvider_is_measurement_supported)},
{"native_start_measurement_collection",
- "()Z",
+ "(Z)Z",
reinterpret_cast<void *>(
android_location_GnssLocationProvider_start_measurement_collection)},
{"native_stop_measurement_collection",
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/coverage/Android.bp b/services/coverage/Android.bp
new file mode 100644
index 0000000..16c9c1b
--- /dev/null
+++ b/services/coverage/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+ name: "services.coverage",
+ srcs: ["java/**/*.java"],
+ libs: ["jacocoagent"],
+}
diff --git a/services/coverage/Android.mk b/services/coverage/Android.mk
deleted file mode 100644
index da99994..0000000
--- a/services/coverage/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services.coverage
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,java)
-
-LOCAL_JAVA_LIBRARIES := jacocoagent
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/devicepolicy/Android.bp b/services/devicepolicy/Android.bp
new file mode 100644
index 0000000..0505204
--- /dev/null
+++ b/services/devicepolicy/Android.bp
@@ -0,0 +1,9 @@
+java_library_static {
+ name: "services.devicepolicy",
+ srcs: ["java/**/*.java"],
+
+ libs: [
+ "conscrypt",
+ "services.core",
+ ],
+}
diff --git a/services/devicepolicy/Android.mk b/services/devicepolicy/Android.mk
deleted file mode 100644
index 7020f17..0000000
--- a/services/devicepolicy/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services.devicepolicy
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,java)
-
-LOCAL_JAVA_LIBRARIES := conscrypt services.core
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
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..7ee047b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -19,6 +19,8 @@
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.ACTION_PROVISION_MANAGED_USER;
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;
@@ -39,10 +41,13 @@
import static android.app.admin.DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL;
import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
import static android.app.admin.DevicePolicyManager.DELEGATION_ENABLE_SYSTEM_APP;
+import static android.app.admin.DevicePolicyManager.DELEGATION_INSTALL_EXISTING_PACKAGE;
import static android.app.admin.DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES;
import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
+import static android.app.admin.DevicePolicyManager.LEAVE_ALL_SYSTEM_APPS_ENABLED;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
import static android.app.admin.DevicePolicyManager.START_USER_IN_BACKGROUND;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
@@ -78,7 +83,6 @@
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
-import android.app.admin.IDevicePolicyManager;
import android.app.admin.NetworkEvent;
import android.app.admin.PasswordMetrics;
import android.app.admin.SecurityLog;
@@ -150,6 +154,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 +205,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;
@@ -210,11 +219,12 @@
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Function;
/**
* Implementation of the device policy APIs.
*/
-public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
protected static final String LOG_TAG = "DevicePolicyManager";
@@ -283,6 +293,8 @@
private static final String ATTR_APPLICATION_RESTRICTIONS_MANAGER
= "application-restrictions-manager";
+ private static final String MANAGED_PROVISIONING_PKG = "com.android.managedprovisioning";
+
// Comprehensive list of delegations.
private static final String DELEGATIONS[] = {
DELEGATION_CERT_INSTALL,
@@ -291,7 +303,9 @@
DELEGATION_ENABLE_SYSTEM_APP,
DELEGATION_KEEP_UNINSTALLED_PACKAGES,
DELEGATION_PACKAGE_ACCESS,
- DELEGATION_PERMISSION_GRANT
+ DELEGATION_PERMISSION_GRANT,
+ DELEGATION_INSTALL_EXISTING_PACKAGE,
+ DELEGATION_KEEP_UNINSTALLED_PACKAGES
};
/**
@@ -313,6 +327,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 +354,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);
}
/**
@@ -376,6 +396,7 @@
private final LockPatternUtils mLockPatternUtils;
private final DevicePolicyConstants mConstants;
private final DeviceAdminServiceController mDeviceAdminServiceController;
+ private final OverlayPackagesProvider mOverlayPackagesProvider;
/**
* Contains (package-user) pairs to remove. An entry (p, u) implies that removal of package p
@@ -451,11 +472,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 +749,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_ENABLED = "is_logout_enabled";
final DeviceAdminInfo info;
@@ -731,7 +766,7 @@
static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
@NonNull
PasswordMetrics minimumPasswordMetrics = new PasswordMetrics(
- DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, DEF_MINIMUM_PASSWORD_LENGTH,
+ PASSWORD_QUALITY_UNSPECIFIED, DEF_MINIMUM_PASSWORD_LENGTH,
DEF_MINIMUM_PASSWORD_LETTERS, DEF_MINIMUM_PASSWORD_UPPER_CASE,
DEF_MINIMUM_PASSWORD_LOWER_CASE, DEF_MINIMUM_PASSWORD_NUMERIC,
DEF_MINIMUM_PASSWORD_SYMBOLS, DEF_MINIMUM_PASSWORD_NON_LETTER);
@@ -764,6 +799,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 isLogoutEnabled = 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;
@@ -856,8 +892,7 @@
out.startTag(null, TAG_POLICIES);
info.writePoliciesToXml(out);
out.endTag(null, TAG_POLICIES);
- if (minimumPasswordMetrics.quality
- != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+ if (minimumPasswordMetrics.quality != PASSWORD_QUALITY_UNSPECIFIED) {
out.startTag(null, TAG_PASSWORD_QUALITY);
out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordMetrics.quality));
out.endTag(null, TAG_PASSWORD_QUALITY);
@@ -1081,6 +1116,11 @@
out.text(organizationName);
out.endTag(null, TAG_ORGANIZATION_NAME);
}
+ if (isLogoutEnabled) {
+ out.startTag(null, TAG_IS_LOGOUT_ENABLED);
+ out.attribute(null, ATTR_VALUE, Boolean.toString(isLogoutEnabled));
+ out.endTag(null, TAG_IS_LOGOUT_ENABLED);
+ }
}
void writePackageListToXml(XmlSerializer out, String outerTag,
@@ -1254,6 +1294,9 @@
} else {
Log.w(LOG_TAG, "Missing text when loading organization name");
}
+ } else if (TAG_IS_LOGOUT_ENABLED.equals(tag)) {
+ isLogoutEnabled = Boolean.parseBoolean(
+ parser.getAttributeValue(null, ATTR_VALUE));
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -1551,6 +1594,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 +1850,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 +1899,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();
@@ -1859,6 +1909,8 @@
mDeviceAdminServiceController = new DeviceAdminServiceController(this, mConstants);
+ mOverlayPackagesProvider = new OverlayPackagesProvider(mContext);
+
if (!mHasFeature) {
// Skip the rest of the initialization
return;
@@ -3033,6 +3085,7 @@
}
@VisibleForTesting
+ @Override
void systemReady(int phase) {
if (!mHasFeature) {
return;
@@ -3099,6 +3152,7 @@
}
}
+ @Override
void handleStartUser(int userId) {
updateScreenCaptureDisabledInWindowManager(userId,
getScreenCaptureDisabled(null, userId));
@@ -3107,10 +3161,12 @@
startOwnerService(userId, "start-user");
}
+ @Override
void handleUnlockUser(int userId) {
startOwnerService(userId, "unlock-user");
}
+ @Override
void handleStopUser(int userId) {
stopOwnerService(userId, "stop-user");
}
@@ -3523,11 +3579,11 @@
@Override
public int getPasswordQuality(ComponentName who, int userHandle, boolean parent) {
if (!mHasFeature) {
- return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+ return PASSWORD_QUALITY_UNSPECIFIED;
}
enforceFullCrossUsersPermission(userHandle);
synchronized (this) {
- int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+ int mode = PASSWORD_QUALITY_UNSPECIFIED;
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
@@ -3610,30 +3666,8 @@
@Override
public int getPasswordMinimumLength(ComponentName who, int userHandle, boolean parent) {
- if (!mHasFeature) {
- return 0;
- }
- enforceFullCrossUsersPermission(userHandle);
- synchronized (this) {
- int length = 0;
-
- if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
- return admin != null ? admin.minimumPasswordMetrics.length : length;
- }
-
- // Return the strictest policy across all participating admins.
- List<ActiveAdmin> admins =
- getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
- final int N = admins.size();
- for (int i = 0; i < N; i++) {
- ActiveAdmin admin = admins.get(i);
- if (length < admin.minimumPasswordMetrics.length) {
- length = admin.minimumPasswordMetrics.length;
- }
- }
- return length;
- }
+ return getStrictestPasswordRequirement(who, userHandle, parent,
+ admin -> admin.minimumPasswordMetrics.length, PASSWORD_QUALITY_UNSPECIFIED);
}
@Override
@@ -3655,31 +3689,8 @@
@Override
public int getPasswordHistoryLength(ComponentName who, int userHandle, boolean parent) {
- if (!mHasFeature) {
- return 0;
- }
- enforceFullCrossUsersPermission(userHandle);
- synchronized (this) {
- int length = 0;
-
- if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
- return admin != null ? admin.passwordHistoryLength : length;
- }
-
- // Return the strictest policy across all participating admins.
- List<ActiveAdmin> admins =
- getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
- final int N = admins.size();
- for (int i = 0; i < N; i++) {
- ActiveAdmin admin = admins.get(i);
- if (length < admin.passwordHistoryLength) {
- length = admin.passwordHistoryLength;
- }
- }
-
- return length;
- }
+ return getStrictestPasswordRequirement(who, userHandle, parent,
+ admin -> admin.passwordHistoryLength, PASSWORD_QUALITY_UNSPECIFIED);
}
@Override
@@ -3868,30 +3879,8 @@
@Override
public int getPasswordMinimumUpperCase(ComponentName who, int userHandle, boolean parent) {
- if (!mHasFeature) {
- return 0;
- }
- enforceFullCrossUsersPermission(userHandle);
- synchronized (this) {
- int length = 0;
-
- if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
- return admin != null ? admin.minimumPasswordMetrics.upperCase : length;
- }
-
- // Return the strictest policy across all participating admins.
- List<ActiveAdmin> admins =
- getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
- final int N = admins.size();
- for (int i = 0; i < N; i++) {
- ActiveAdmin admin = admins.get(i);
- if (length < admin.minimumPasswordMetrics.upperCase) {
- length = admin.minimumPasswordMetrics.upperCase;
- }
- }
- return length;
- }
+ return getStrictestPasswordRequirement(who, userHandle, parent,
+ admin -> admin.minimumPasswordMetrics.upperCase, PASSWORD_QUALITY_COMPLEX);
}
@Override
@@ -3910,30 +3899,8 @@
@Override
public int getPasswordMinimumLowerCase(ComponentName who, int userHandle, boolean parent) {
- if (!mHasFeature) {
- return 0;
- }
- enforceFullCrossUsersPermission(userHandle);
- synchronized (this) {
- int length = 0;
-
- if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
- return admin != null ? admin.minimumPasswordMetrics.lowerCase : length;
- }
-
- // Return the strictest policy across all participating admins.
- List<ActiveAdmin> admins =
- getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
- final int N = admins.size();
- for (int i = 0; i < N; i++) {
- ActiveAdmin admin = admins.get(i);
- if (length < admin.minimumPasswordMetrics.lowerCase) {
- length = admin.minimumPasswordMetrics.lowerCase;
- }
- }
- return length;
- }
+ return getStrictestPasswordRequirement(who, userHandle, parent,
+ admin -> admin.minimumPasswordMetrics.lowerCase, PASSWORD_QUALITY_COMPLEX);
}
@Override
@@ -3955,33 +3922,8 @@
@Override
public int getPasswordMinimumLetters(ComponentName who, int userHandle, boolean parent) {
- if (!mHasFeature) {
- return 0;
- }
- enforceFullCrossUsersPermission(userHandle);
- synchronized (this) {
- int length = 0;
-
- if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
- return admin != null ? admin.minimumPasswordMetrics.letters : length;
- }
-
- // Return the strictest policy across all participating admins.
- List<ActiveAdmin> admins =
- getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
- final int N = admins.size();
- for (int i = 0; i < N; i++) {
- ActiveAdmin admin = admins.get(i);
- if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
- continue;
- }
- if (length < admin.minimumPasswordMetrics.letters) {
- length = admin.minimumPasswordMetrics.letters;
- }
- }
- return length;
- }
+ return getStrictestPasswordRequirement(who, userHandle, parent,
+ admin -> admin.minimumPasswordMetrics.letters, PASSWORD_QUALITY_COMPLEX);
}
@Override
@@ -4003,34 +3945,9 @@
@Override
public int getPasswordMinimumNumeric(ComponentName who, int userHandle, boolean parent) {
- if (!mHasFeature) {
- return 0;
- }
- enforceFullCrossUsersPermission(userHandle);
- synchronized (this) {
- int length = 0;
-
- if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
- return admin != null ? admin.minimumPasswordMetrics.numeric : length;
- }
-
- // Return the strictest policy across all participating admins.
- List<ActiveAdmin> admins =
- getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
- final int N = admins.size();
- for (int i = 0; i < N; i++) {
- ActiveAdmin admin = admins.get(i);
- if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
- continue;
- }
- if (length < admin.minimumPasswordMetrics.numeric) {
- length = admin.minimumPasswordMetrics.numeric;
- }
- }
- return length;
- }
- }
+ return getStrictestPasswordRequirement(who, userHandle, parent,
+ admin -> admin.minimumPasswordMetrics.numeric, PASSWORD_QUALITY_COMPLEX);
+ }
@Override
public void setPasswordMinimumSymbols(ComponentName who, int length, boolean parent) {
@@ -4051,33 +3968,8 @@
@Override
public int getPasswordMinimumSymbols(ComponentName who, int userHandle, boolean parent) {
- if (!mHasFeature) {
- return 0;
- }
- enforceFullCrossUsersPermission(userHandle);
- synchronized (this) {
- int length = 0;
-
- if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
- return admin != null ? admin.minimumPasswordMetrics.symbols : length;
- }
-
- // Return the strictest policy across all participating admins.
- List<ActiveAdmin> admins =
- getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
- final int N = admins.size();
- for (int i = 0; i < N; i++) {
- ActiveAdmin admin = admins.get(i);
- if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
- continue;
- }
- if (length < admin.minimumPasswordMetrics.symbols) {
- length = admin.minimumPasswordMetrics.symbols;
- }
- }
- return length;
- }
+ return getStrictestPasswordRequirement(who, userHandle, parent,
+ admin -> admin.minimumPasswordMetrics.symbols, PASSWORD_QUALITY_COMPLEX);
}
@Override
@@ -4099,32 +3991,40 @@
@Override
public int getPasswordMinimumNonLetter(ComponentName who, int userHandle, boolean parent) {
+ return getStrictestPasswordRequirement(who, userHandle, parent,
+ admin -> admin.minimumPasswordMetrics.nonLetter, PASSWORD_QUALITY_COMPLEX);
+ }
+
+ /**
+ * Calculates strictest (maximum) value for a given password property enforced by admin[s].
+ */
+ private int getStrictestPasswordRequirement(ComponentName who, int userHandle,
+ boolean parent, Function<ActiveAdmin, Integer> getter, int minimumPasswordQuality) {
if (!mHasFeature) {
return 0;
}
enforceFullCrossUsersPermission(userHandle);
synchronized (this) {
- int length = 0;
-
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
- return admin != null ? admin.minimumPasswordMetrics.nonLetter : length;
+ final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
+ return admin != null ? getter.apply(admin) : 0;
}
- // Return the strictest policy across all participating admins.
- List<ActiveAdmin> admins =
+ int maxValue = 0;
+ final List<ActiveAdmin> admins =
getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
final int N = admins.size();
for (int i = 0; i < N; i++) {
- ActiveAdmin admin = admins.get(i);
- if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
+ final ActiveAdmin admin = admins.get(i);
+ if (!isLimitPasswordAllowed(admin, minimumPasswordQuality)) {
continue;
}
- if (length < admin.minimumPasswordMetrics.nonLetter) {
- length = admin.minimumPasswordMetrics.nonLetter;
+ final Integer adminValue = getter.apply(admin);
+ if (adminValue > maxValue) {
+ maxValue = adminValue;
}
}
- return length;
+ return maxValue;
}
}
@@ -4164,7 +4064,7 @@
private boolean isActivePasswordSufficientForUserLocked(
DevicePolicyData policy, int userHandle, boolean parent) {
final int requiredPasswordQuality = getPasswordQuality(null, userHandle, parent);
- if (requiredPasswordQuality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+ if (requiredPasswordQuality == PASSWORD_QUALITY_UNSPECIFIED) {
// A special case is when there is no required password quality, then we just return
// true since any password would be sufficient. This is for the scenario when a work
// profile is first created so there is no information about the current password but
@@ -4404,10 +4304,10 @@
synchronized (this) {
quality = getPasswordQuality(null, userHandle, /* parent */ false);
if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
- quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+ quality = PASSWORD_QUALITY_UNSPECIFIED;
}
final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
- if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+ if (quality != PASSWORD_QUALITY_UNSPECIFIED) {
final int realQuality = metrics.quality;
if (realQuality < quality
&& quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
@@ -4979,6 +4879,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 +6891,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);
@@ -8220,6 +8173,7 @@
final boolean ephemeral = (flags & DevicePolicyManager.MAKE_USER_EPHEMERAL) != 0;
final boolean demo = (flags & DevicePolicyManager.MAKE_USER_DEMO) != 0
&& UserManager.isDeviceInDemoMode(mContext);
+ final boolean leaveAllSystemAppsEnabled = (flags & LEAVE_ALL_SYSTEM_APPS_ENABLED) != 0;
// Create user.
UserHandle user = null;
synchronized (this) {
@@ -8234,8 +8188,14 @@
if (demo) {
userInfoFlags |= UserInfo.FLAG_DEMO;
}
+ String[] disallowedPackages = null;
+ if (!leaveAllSystemAppsEnabled) {
+ disallowedPackages = mOverlayPackagesProvider.getNonRequiredApps(admin,
+ UserHandle.myUserId(), ACTION_PROVISION_MANAGED_USER).toArray(
+ new String[0]);
+ }
UserInfo userInfo = mUserManagerInternal.createUserEvenWhenDisallowed(name,
- userInfoFlags);
+ userInfoFlags, disallowedPackages);
if (userInfo != null) {
user = userInfo.getUserHandle();
}
@@ -8246,11 +8206,20 @@
if (user == null) {
return null;
}
+
+ final int userHandle = user.getIdentifier();
+ final Intent intent = new Intent(DevicePolicyManager.ACTION_MANAGED_USER_CREATED)
+ .putExtra(Intent.EXTRA_USER_HANDLE, userHandle)
+ .putExtra(
+ DevicePolicyManager.EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED,
+ leaveAllSystemAppsEnabled)
+ .setPackage(MANAGED_PROVISIONING_PKG)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+
final long id = mInjector.binderClearCallingIdentity();
try {
final String adminPkg = admin.getPackageName();
-
- final int userHandle = user.getIdentifier();
try {
// Install the profile owner if not present.
if (!mIPackageManager.isPackageAvailable(adminPkg, userHandle)) {
@@ -8280,7 +8249,7 @@
if ((flags & START_USER_IN_BACKGROUND) != 0) {
try {
- mInjector.getIActivityManager().startUserInBackground(user.getIdentifier());
+ mInjector.getIActivityManager().startUserInBackground(userHandle);
} catch (RemoteException re) {
// Does not happen, same process
}
@@ -8288,7 +8257,7 @@
return user;
} catch (Throwable re) {
- mUserManager.removeUser(user.getIdentifier());
+ mUserManager.removeUser(userHandle);
return null;
} finally {
mInjector.binderRestoreCallingIdentity(id);
@@ -8356,6 +8325,106 @@
}
@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 boolean isEphemeralUser(ComponentName who) {
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ synchronized (this) {
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ }
+
+ final int callingUserId = mInjector.userHandleGetCallingUserId();
+ final long id = mInjector.binderClearCallingIdentity();
+ try {
+ return mInjector.getUserManager().isUserEphemeral(callingUserId);
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
+ }
+
+ @Override
public Bundle getApplicationRestrictions(ComponentName who, String callerPackage,
String packageName) {
enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
@@ -8661,6 +8730,39 @@
}
@Override
+ public boolean installExistingPackage(ComponentName who, String callerPackage,
+ String packageName) {
+ synchronized (this) {
+ // Ensure the caller is a PO or an install existing package delegate
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_INSTALL_EXISTING_PACKAGE);
+ final int callingUserId = mInjector.userHandleGetCallingUserId();
+ if (!isUserAffiliatedWithDeviceLocked(callingUserId)) {
+ throw new SecurityException("Admin " + who +
+ " is neither the device owner or affiliated user's profile owner.");
+ }
+
+ final long id = mInjector.binderClearCallingIdentity();
+ try {
+ if (VERBOSE_LOG) {
+ Slog.v(LOG_TAG, "installing " + packageName + " for "
+ + callingUserId);
+ }
+
+ // Install the package.
+ return mIPackageManager.installExistingPackageAsUser(packageName, callingUserId,
+ 0 /*installFlags*/, PackageManager.INSTALL_REASON_POLICY)
+ == PackageManager.INSTALL_SUCCEEDED;
+ } catch (RemoteException re) {
+ // shouldn't happen
+ return false;
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
+ }
+ }
+
+ @Override
public void setAccountManagementDisabled(ComponentName who, String accountType,
boolean disabled) {
if (!mHasFeature) {
@@ -9110,6 +9212,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 +9356,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 +9385,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 +9654,11 @@
}
return null;
}
+
+ @Override
+ public boolean isUserAffiliatedWithDevice(int userId) {
+ return DevicePolicyManagerService.this.isUserAffiliatedWithDeviceLocked(userId);
+ }
}
private Intent createShowAdminSupportIntent(ComponentName admin, int userId) {
@@ -11341,8 +11474,8 @@
long ident = mInjector.binderClearCallingIdentity();
try {
- return ActivityManager.getService().clearApplicationUserData(packageName, callback,
- userId);
+ return ActivityManager.getService().clearApplicationUserData(packageName, false,
+ callback, userId);
} catch(RemoteException re) {
// Same process, should not happen.
} catch (SecurityException se) {
@@ -11365,4 +11498,44 @@
}
return false;
}
+
+ @Override
+ public synchronized void setLogoutEnabled(ComponentName admin, boolean enabled) {
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(admin);
+ getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+
+ if (enabled == isLogoutEnabledInternalLocked()) {
+ // already in the requested state
+ return;
+ }
+ ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+ deviceOwner.isLogoutEnabled = enabled;
+ saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ }
+
+ @Override
+ public boolean isLogoutEnabled() {
+ if (!mHasFeature) {
+ return false;
+ }
+ synchronized (this) {
+ return isLogoutEnabledInternalLocked();
+ }
+ }
+
+ private boolean isLogoutEnabledInternalLocked() {
+ ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+ return (deviceOwner != null) && deviceOwner.isLogoutEnabled;
+ }
+
+ @Override
+ public List<String> getDisallowedSystemApps(ComponentName admin, int userId,
+ String provisioningAction) throws RemoteException {
+ enforceCanManageProfileAndDeviceOwners();
+ return new ArrayList<>(
+ mOverlayPackagesProvider.getNonRequiredApps(admin, userId, provisioningAction));
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
new file mode 100644
index 0000000..d0ec0ee
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.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 com.android.server.devicepolicy;
+
+import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
+import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
+import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.app.admin.DeviceAdminReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.ArraySet;
+import android.view.inputmethod.InputMethodInfo;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.view.IInputMethodManager;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Class that provides the apps that are not required on a managed device / profile according to the
+ * overlays provided via (vendor_|)required_apps_managed_(profile|device).xml.
+ */
+public class OverlayPackagesProvider {
+
+ protected static final String TAG = "OverlayPackagesProvider";
+
+ private final PackageManager mPm;
+ private final IInputMethodManager mIInputMethodManager;
+ private final Context mContext;
+
+ public OverlayPackagesProvider(Context context) {
+ this(context, getIInputMethodManager());
+ }
+
+ @VisibleForTesting
+ OverlayPackagesProvider(Context context, IInputMethodManager iInputMethodManager) {
+ mContext = context;
+ mPm = checkNotNull(context.getPackageManager());
+ mIInputMethodManager = checkNotNull(iInputMethodManager);
+ }
+
+ /**
+ * Computes non-required apps. All the system apps with a launcher that are not in
+ * the required set of packages will be considered as non-required apps.
+ *
+ * Note: If an app is mistakenly listed as both required and disallowed, it will be treated as
+ * disallowed.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param userId The userId for which the non-required apps needs to be computed.
+ * @param provisioningAction action indicating type of provisioning, should be one of
+ * {@link ACTION_PROVISION_MANAGED_DEVICE}, {@link
+ * ACTION_PROVISION_MANAGED_PROFILE} or
+ * {@link ACTION_PROVISION_MANAGED_USER}.
+ * @return the set of non-required apps.
+ */
+ @NonNull
+ public Set<String> getNonRequiredApps(@NonNull ComponentName admin, int userId,
+ @NonNull String provisioningAction) {
+ final Set<String> nonRequiredApps = getLaunchableApps(userId);
+ // Newly installed system apps are uninstalled when they are not required and are either
+ // disallowed or have a launcher icon.
+ nonRequiredApps.removeAll(getRequiredApps(provisioningAction, admin.getPackageName()));
+ // Don't delete the system input method packages in case of Device owner provisioning.
+ if (ACTION_PROVISION_MANAGED_DEVICE.equals(provisioningAction)
+ || ACTION_PROVISION_MANAGED_USER.equals(provisioningAction)) {
+ nonRequiredApps.removeAll(getSystemInputMethods());
+ }
+ nonRequiredApps.addAll(getDisallowedApps(provisioningAction));
+ return nonRequiredApps;
+ }
+
+ private Set<String> getLaunchableApps(int userId) {
+ final Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
+ launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ final List<ResolveInfo> resolveInfos = mPm.queryIntentActivitiesAsUser(launcherIntent,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ userId);
+ final Set<String> apps = new ArraySet<>();
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ apps.add(resolveInfo.activityInfo.packageName);
+ }
+ return apps;
+ }
+
+ private Set<String> getSystemInputMethods() {
+ // InputMethodManager is final so it cannot be mocked.
+ // So, we're using IInputMethodManager directly because it can be mocked.
+ final List<InputMethodInfo> inputMethods;
+ try {
+ inputMethods = mIInputMethodManager.getInputMethodList();
+ } catch (RemoteException e) {
+ // Should not happen
+ return null;
+ }
+ final Set<String> systemInputMethods = new ArraySet<>();
+ for (InputMethodInfo inputMethodInfo : inputMethods) {
+ ApplicationInfo applicationInfo = inputMethodInfo.getServiceInfo().applicationInfo;
+ if (applicationInfo.isSystemApp()) {
+ systemInputMethods.add(inputMethodInfo.getPackageName());
+ }
+ }
+ return systemInputMethods;
+ }
+
+ private Set<String> getRequiredApps(String provisioningAction, String dpcPackageName) {
+ final Set<String> requiredApps = new ArraySet<>();
+ requiredApps.addAll(getRequiredAppsSet(provisioningAction));
+ requiredApps.addAll(getVendorRequiredAppsSet(provisioningAction));
+ requiredApps.add(dpcPackageName);
+ return requiredApps;
+ }
+
+ private Set<String> getDisallowedApps(String provisioningAction) {
+ final Set<String> disallowedApps = new ArraySet<>();
+ disallowedApps.addAll(getDisallowedAppsSet(provisioningAction));
+ disallowedApps.addAll(getVendorDisallowedAppsSet(provisioningAction));
+ return disallowedApps;
+ }
+
+ private static IInputMethodManager getIInputMethodManager() {
+ final IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
+ return IInputMethodManager.Stub.asInterface(b);
+ }
+
+ private Set<String> getRequiredAppsSet(String provisioningAction) {
+ final int resId;
+ switch (provisioningAction) {
+ case ACTION_PROVISION_MANAGED_USER:
+ resId = R.array.required_apps_managed_user;
+ break;
+ case ACTION_PROVISION_MANAGED_PROFILE:
+ resId = R.array.required_apps_managed_profile;
+ break;
+ case ACTION_PROVISION_MANAGED_DEVICE:
+ resId = R.array.required_apps_managed_device;
+ break;
+ default:
+ throw new IllegalArgumentException("Provisioning type "
+ + provisioningAction + " not supported.");
+ }
+ return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
+ }
+
+ private Set<String> getDisallowedAppsSet(String provisioningAction) {
+ final int resId;
+ switch (provisioningAction) {
+ case ACTION_PROVISION_MANAGED_USER:
+ resId = R.array.disallowed_apps_managed_user;
+ break;
+ case ACTION_PROVISION_MANAGED_PROFILE:
+ resId = R.array.disallowed_apps_managed_profile;
+ break;
+ case ACTION_PROVISION_MANAGED_DEVICE:
+ resId = R.array.disallowed_apps_managed_device;
+ break;
+ default:
+ throw new IllegalArgumentException("Provisioning type "
+ + provisioningAction + " not supported.");
+ }
+ return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
+ }
+
+ private Set<String> getVendorRequiredAppsSet(String provisioningAction) {
+ final int resId;
+ switch (provisioningAction) {
+ case ACTION_PROVISION_MANAGED_USER:
+ resId = R.array.vendor_required_apps_managed_user;
+ break;
+ case ACTION_PROVISION_MANAGED_PROFILE:
+ resId = R.array.vendor_required_apps_managed_profile;
+ break;
+ case ACTION_PROVISION_MANAGED_DEVICE:
+ resId = R.array.vendor_required_apps_managed_device;
+ break;
+ default:
+ throw new IllegalArgumentException("Provisioning type "
+ + provisioningAction + " not supported.");
+ }
+ return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
+ }
+
+ private Set<String> getVendorDisallowedAppsSet(String provisioningAction) {
+ final int resId;
+ switch (provisioningAction) {
+ case ACTION_PROVISION_MANAGED_USER:
+ resId = R.array.vendor_disallowed_apps_managed_user;
+ break;
+ case ACTION_PROVISION_MANAGED_PROFILE:
+ resId = R.array.vendor_disallowed_apps_managed_profile;
+ break;
+ case ACTION_PROVISION_MANAGED_DEVICE:
+ resId = R.array.vendor_disallowed_apps_managed_device;
+ break;
+ default:
+ throw new IllegalArgumentException("Provisioning type "
+ + provisioningAction + " not supported.");
+ }
+ return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 33f4e34..7aa628a 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");
@@ -1084,14 +1088,17 @@
}
traceEnd();
- // Wifi Service must be started first for wifi-related services.
- traceBeginAndSlog("StartWifi");
- mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
- traceEnd();
- traceBeginAndSlog("StartWifiScanning");
- mSystemServiceManager.startService(
- "com.android.server.wifi.scanner.WifiScanningService");
- traceEnd();
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI)) {
+ // Wifi Service must be started first for wifi-related services.
+ traceBeginAndSlog("StartWifi");
+ mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
+ traceEnd();
+ traceBeginAndSlog("StartWifiScanning");
+ mSystemServiceManager.startService(
+ "com.android.server.wifi.scanner.WifiScanningService");
+ traceEnd();
+ }
if (!disableRtt) {
traceBeginAndSlog("StartWifiRtt");
@@ -1523,6 +1530,12 @@
}
}
+ if (!disableSlices) {
+ traceBeginAndSlog("StartSliceManagerService");
+ mSystemServiceManager.startService(SLICE_MANAGER_SERVICE_CLASS);
+ traceEnd();
+ }
+
if (!disableCameraService) {
traceBeginAndSlog("StartCameraServiceProxy");
mSystemServiceManager.startService(CameraServiceProxy.class);
diff --git a/services/midi/Android.bp b/services/midi/Android.bp
new file mode 100644
index 0000000..3745e89
--- /dev/null
+++ b/services/midi/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+ name: "services.midi",
+ srcs: ["java/**/*.java"],
+ libs: ["services.core"],
+}
diff --git a/services/midi/Android.mk b/services/midi/Android.mk
deleted file mode 100644
index faac01c..0000000
--- a/services/midi/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services.midi
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,java)
-
-LOCAL_JAVA_LIBRARIES := services.core
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/net/Android.bp b/services/net/Android.bp
new file mode 100644
index 0000000..e0ae68f
--- /dev/null
+++ b/services/net/Android.bp
@@ -0,0 +1,4 @@
+java_library_static {
+ name: "services.net",
+ srcs: ["java/**/*.java"],
+}
diff --git a/services/net/Android.mk b/services/net/Android.mk
deleted file mode 100644
index 408794e..0000000
--- a/services/net/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services.net
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,java)
-
-LOCAL_AIDL_INCLUDES += \
- system/netd/server/binder
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/net/OWNERS b/services/net/OWNERS
index 2d71c20..6f77e04 100644
--- a/services/net/OWNERS
+++ b/services/net/OWNERS
@@ -1,10 +1,7 @@
set noparent
-per-file Android.mk = build.master@android.com
-per-file Android.mk = ek@google.com
-per-file Android.mk = hugobenichi@google.com
-per-file Android.mk = lorenzo@google.com
-
ek@google.com
hugobenichi@google.com
+jchalard@google.com
lorenzo@google.com
+satk@google.com
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..fdb366c 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -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
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/Android.bp b/services/print/Android.bp
new file mode 100644
index 0000000..80a8c75
--- /dev/null
+++ b/services/print/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+ name: "services.print",
+ srcs: ["java/**/*.java"],
+ libs: ["services.core"],
+}
diff --git a/services/print/Android.mk b/services/print/Android.mk
deleted file mode 100644
index 00eb2e4..0000000
--- a/services/print/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services.print
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,java)
-
-LOCAL_JAVA_LIBRARIES := services.core
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
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/restrictions/Android.bp b/services/restrictions/Android.bp
new file mode 100644
index 0000000..979e891
--- /dev/null
+++ b/services/restrictions/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+ name: "services.restrictions",
+ srcs: ["java/**/*.java"],
+ libs: ["services.core"],
+}
diff --git a/services/restrictions/Android.mk b/services/restrictions/Android.mk
deleted file mode 100644
index 57d1c46..0000000
--- a/services/restrictions/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services.restrictions
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,java)
-
-LOCAL_JAVA_LIBRARIES := services.core
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index 114929c..b5e4af7 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -40,15 +40,15 @@
# Include the testing libraries (JUnit4 + Robolectric libs).
LOCAL_STATIC_JAVA_LIBRARIES := \
+ platform-robolectric-android-all-stubs \
android-support-test \
mockito-robolectric-prebuilt \
platform-test-annotations \
truth-prebuilt
-# TODO(b/69254249): Migrate to Robolectric 3.4.2
LOCAL_JAVA_LIBRARIES := \
junit \
- platform-robolectric-3.1.1-prebuilt
+ platform-robolectric-3.5.1-prebuilt
LOCAL_INSTRUMENTATION_FOR := FrameworksServicesLib
LOCAL_MODULE := FrameworksServicesRoboTests
@@ -73,5 +73,4 @@
LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))backup/java
-# TODO(b/69254249): Migrate to Robolectric 3.4.2
-include prebuilts/misc/common/robolectric/3.1.1/run_robotests.mk
+include prebuilts/misc/common/robolectric/3.5.1/run_robotests.mk
diff --git a/services/robotests/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
index 2824b35..2cb4a69 100644
--- a/services/robotests/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
+import static org.robolectric.shadow.api.Shadow.extract;
import android.app.backup.BackupManager;
import android.content.ComponentName;
@@ -31,23 +32,25 @@
import android.platform.test.annotations.Presubmit;
import com.android.server.backup.testing.BackupTransportStub;
-import com.android.server.backup.testing.DefaultPackageManagerWithQueryIntentServicesAsUser;
import com.android.server.backup.testing.ShadowBackupTransportStub;
import com.android.server.backup.testing.ShadowContextImplForBackup;
+import com.android.server.backup.testing.ShadowPackageManagerForBackup;
import com.android.server.backup.testing.TransportBoundListenerStub;
import com.android.server.backup.testing.TransportReadyCallbackStub;
+import com.android.server.backup.transport.TransportClient;
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderClasses;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
-import org.robolectric.res.builder.RobolectricPackageManager;
import org.robolectric.shadows.ShadowLog;
import org.robolectric.shadows.ShadowLooper;
+import org.robolectric.shadows.ShadowPackageManager;
import java.util.ArrayList;
import java.util.Arrays;
@@ -55,15 +58,17 @@
import java.util.HashSet;
import java.util.List;
-@RunWith(RobolectricTestRunner.class)
+@RunWith(FrameworkRobolectricTestRunner.class)
@Config(
manifest = Config.NONE,
- sdk = 23,
+ sdk = 26,
shadows = {
ShadowContextImplForBackup.class,
- ShadowBackupTransportStub.class
+ ShadowBackupTransportStub.class,
+ ShadowPackageManagerForBackup.class
}
)
+@SystemLoaderClasses({TransportManager.class})
@Presubmit
public class TransportManagerTest {
private static final String PACKAGE_NAME = "some.package.name";
@@ -72,7 +77,7 @@
private TransportInfo mTransport1;
private TransportInfo mTransport2;
- private RobolectricPackageManager mPackageManager;
+ private ShadowPackageManager mPackageManagerShadow;
private final TransportBoundListenerStub mTransportBoundListenerStub =
new TransportBoundListenerStub(true);
@@ -85,9 +90,10 @@
MockitoAnnotations.initMocks(this);
ShadowLog.stream = System.out;
- mPackageManager = new DefaultPackageManagerWithQueryIntentServicesAsUser(
- RuntimeEnvironment.getAppResourceLoader());
- RuntimeEnvironment.setRobolectricPackageManager(mPackageManager);
+
+ mPackageManagerShadow =
+ (ShadowPackageManagerForBackup)
+ extract(RuntimeEnvironment.application.getPackageManager());
mTransport1 = new TransportInfo(PACKAGE_NAME, "transport1.name");
mTransport2 = new TransportInfo(PACKAGE_NAME, "transport2.name");
@@ -475,6 +481,74 @@
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");
+ }
+
+ @Test
+ public void isTransportRegistered_returnsCorrectly() throws Exception {
+ TransportManager transportManager =
+ createTransportManagerAndSetUpTransports(
+ Collections.singletonList(mTransport1),
+ Collections.singletonList(mTransport2),
+ mTransport1.name);
+
+ assertThat(transportManager.isTransportRegistered(mTransport1.name)).isTrue();
+ assertThat(transportManager.isTransportRegistered(mTransport2.name)).isFalse();
+ }
+
private void setUpPackageWithTransports(String packageName, List<TransportInfo> transports,
int flags) throws Exception {
PackageInfo packageInfo = new PackageInfo();
@@ -482,7 +556,7 @@
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.privateFlags = flags;
- mPackageManager.addPackage(packageInfo);
+ mPackageManagerShadow.addPackage(packageInfo);
List<ResolveInfo> transportsInfo = new ArrayList<>();
for (TransportInfo transport : transports) {
@@ -496,7 +570,7 @@
Intent intent = new Intent(TransportManager.SERVICE_ACTION_TRANSPORT_HOST);
intent.setPackage(packageName);
- mPackageManager.addResolveInfoForIntent(intent, transportsInfo);
+ mPackageManagerShadow.addResolveInfoForIntent(intent, transportsInfo);
}
private TransportManager createTransportManagerAndSetUpTransports(
diff --git a/services/robotests/src/com/android/server/backup/testing/DefaultPackageManagerWithQueryIntentServicesAsUser.java b/services/robotests/src/com/android/server/backup/testing/ShadowPackageManagerForBackup.java
similarity index 69%
rename from services/robotests/src/com/android/server/backup/testing/DefaultPackageManagerWithQueryIntentServicesAsUser.java
rename to services/robotests/src/com/android/server/backup/testing/ShadowPackageManagerForBackup.java
index 5a0967b..b64b59d 100644
--- a/services/robotests/src/com/android/server/backup/testing/DefaultPackageManagerWithQueryIntentServicesAsUser.java
+++ b/services/robotests/src/com/android/server/backup/testing/ShadowPackageManagerForBackup.java
@@ -16,28 +16,22 @@
package com.android.server.backup.testing;
+import android.app.ApplicationPackageManager;
import android.content.Intent;
import android.content.pm.ResolveInfo;
-import org.robolectric.res.ResourceLoader;
-import org.robolectric.res.builder.DefaultPackageManager;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowApplicationPackageManager;
import java.util.List;
/**
* Implementation of PackageManager for Robolectric which handles queryIntentServicesAsUser().
*/
-public class DefaultPackageManagerWithQueryIntentServicesAsUser extends
- DefaultPackageManager {
-
- /* package */
- public DefaultPackageManagerWithQueryIntentServicesAsUser(
- ResourceLoader appResourceLoader) {
- super(appResourceLoader);
- }
-
+@Implements(value = ApplicationPackageManager.class, inheritImplementationMethods = true)
+public class ShadowPackageManagerForBackup extends ShadowApplicationPackageManager {
@Override
public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) {
- return super.queryIntentServices(intent, flags);
+ return queryIntentServices(intent, flags);
}
}
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..4462d2a 100644
--- a/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
+++ b/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
@@ -18,6 +18,8 @@
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;
import static org.mockito.ArgumentMatchers.eq;
@@ -36,30 +38,34 @@
import android.platform.test.annotations.Presubmit;
import com.android.internal.backup.IBackupTransport;
+import com.android.server.backup.TransportManager;
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderClasses;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLooper;
-@RunWith(RobolectricTestRunner.class)
-@Config(manifest = Config.NONE, sdk = 23)
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderClasses({TransportManager.class, TransportClient.class})
@Presubmit
public class TransportClientTest {
private static final String PACKAGE_NAME = "some.package.name";
- private static final ComponentName TRANSPORT_COMPONENT =
- new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".transport.Transport");
@Mock private Context mContext;
@Mock private TransportConnectionListener mTransportConnectionListener;
@Mock private TransportConnectionListener mTransportConnectionListener2;
@Mock private IBackupTransport.Stub mIBackupTransport;
private TransportClient mTransportClient;
+ private ComponentName mTransportComponent;
+ private String mTransportDirName;
private Intent mBindIntent;
private ShadowLooper mShadowLooper;
@@ -69,10 +75,18 @@
Looper mainLooper = Looper.getMainLooper();
mShadowLooper = shadowOf(mainLooper);
- mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(TRANSPORT_COMPONENT);
+ mTransportComponent =
+ new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".transport.Transport");
+ mTransportDirName = mTransportComponent.toString();
+ mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent);
mTransportClient =
new TransportClient(
- mContext, mBindIntent, TRANSPORT_COMPONENT, "1", new Handler(mainLooper));
+ mContext,
+ mBindIntent,
+ mTransportComponent,
+ mTransportDirName,
+ "1",
+ new Handler(mainLooper));
when(mContext.bindServiceAsUser(
eq(mBindIntent),
@@ -82,7 +96,16 @@
.thenReturn(true);
}
- // TODO: Testing implementation? Remove?
+ @Test
+ public void testGetTransportDirName_returnsTransportDirName() {
+ assertThat(mTransportClient.getTransportDirName()).isEqualTo(mTransportDirName);
+ }
+
+ @Test
+ public void testGetTransportComponent_returnsTransportComponent() {
+ assertThat(mTransportClient.getTransportComponent()).isEqualTo(mTransportComponent);
+ }
+
@Test
public void testConnectAsync_callsBindService() throws Exception {
mTransportClient.connectAsync(mTransportConnectionListener, "caller");
@@ -101,7 +124,7 @@
// Simulate framework connecting
ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext);
- connection.onServiceConnected(TRANSPORT_COMPONENT, mIBackupTransport);
+ connection.onServiceConnected(mTransportComponent, mIBackupTransport);
mShadowLooper.runToEndOfTasks();
verify(mTransportConnectionListener)
@@ -116,7 +139,7 @@
mTransportClient.connectAsync(mTransportConnectionListener2, "caller2");
- connection.onServiceConnected(TRANSPORT_COMPONENT, mIBackupTransport);
+ connection.onServiceConnected(mTransportComponent, mIBackupTransport);
mShadowLooper.runToEndOfTasks();
verify(mTransportConnectionListener)
@@ -129,7 +152,7 @@
public void testConnectAsync_whenAlreadyConnected_callsListener() throws Exception {
mTransportClient.connectAsync(mTransportConnectionListener, "caller1");
ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext);
- connection.onServiceConnected(TRANSPORT_COMPONENT, mIBackupTransport);
+ connection.onServiceConnected(mTransportComponent, mIBackupTransport);
mTransportClient.connectAsync(mTransportConnectionListener2, "caller2");
@@ -174,8 +197,8 @@
throws Exception {
mTransportClient.connectAsync(mTransportConnectionListener, "caller1");
ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext);
- connection.onServiceConnected(TRANSPORT_COMPONENT, mIBackupTransport);
- connection.onServiceDisconnected(TRANSPORT_COMPONENT);
+ connection.onServiceConnected(mTransportComponent, mIBackupTransport);
+ connection.onServiceDisconnected(mTransportComponent);
mTransportClient.connectAsync(mTransportConnectionListener2, "caller1");
@@ -188,9 +211,9 @@
throws Exception {
mTransportClient.connectAsync(mTransportConnectionListener, "caller1");
ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext);
- connection.onServiceConnected(TRANSPORT_COMPONENT, mIBackupTransport);
- connection.onServiceDisconnected(TRANSPORT_COMPONENT);
- connection.onServiceConnected(TRANSPORT_COMPONENT, mIBackupTransport);
+ connection.onServiceConnected(mTransportComponent, mIBackupTransport);
+ connection.onServiceDisconnected(mTransportComponent);
+ connection.onServiceConnected(mTransportComponent, mIBackupTransport);
mTransportClient.connectAsync(mTransportConnectionListener2, "caller1");
@@ -205,7 +228,7 @@
mTransportClient.connectAsync(mTransportListener, "caller");
ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext);
- connection.onBindingDied(TRANSPORT_COMPONENT);
+ connection.onBindingDied(mTransportComponent);
mShadowLooper.runToEndOfTasks();
verify(mTransportListener).onTransportBound(isNull(), eq(mTransportClient));
@@ -219,7 +242,7 @@
mTransportClient.connectAsync(mTransportListener2, "caller2");
- connection.onBindingDied(TRANSPORT_COMPONENT);
+ connection.onBindingDied(mTransportComponent);
mShadowLooper.runToEndOfTasks();
verify(mTransportListener).onTransportBound(isNull(), eq(mTransportClient));
diff --git a/services/robotests/src/com/android/server/testing/FrameworkRobolectricTestRunner.java b/services/robotests/src/com/android/server/testing/FrameworkRobolectricTestRunner.java
new file mode 100644
index 0000000..78ac4ed
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/FrameworkRobolectricTestRunner.java
@@ -0,0 +1,162 @@
+/*
+ * 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.testing;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.internal.SandboxFactory;
+import org.robolectric.internal.SdkEnvironment;
+import org.robolectric.internal.bytecode.InstrumentationConfiguration;
+import org.robolectric.internal.bytecode.SandboxClassLoader;
+import org.robolectric.util.Util;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+/**
+ * HACK
+ * Robolectric loads up Android environment from prebuilt android jars before running a method.
+ * These jars are versioned according to the SDK level configured for the method (or class). The
+ * jars represent a snapshot of the Android APIs in that SDK level. For Robolectric tests that are
+ * testing Android components themselves we don't want certain classes (usually the
+ * class-under-test) to be loaded from the prebuilt jar, we want it instead to be loaded from the
+ * dependencies of our test target, i.e. the system class loader. That way we can write tests
+ * against the actual classes that are in the tree, not a past version of them. Ideally we would
+ * have a locally built jar referenced by Robolectric, but until that happens one can use this
+ * class.
+ * This class reads the {@link SystemLoaderClasses} annotation on test classes and for each class
+ * in that annotation value it will bypass the android jar and load it from the system class loader.
+ * Allowing the test to test the actual class in the tree.
+ *
+ * Implementation note: One could think about overriding
+ * {@link RobolectricTestRunner#createClassLoaderConfig(FrameworkMethod)} method and putting the
+ * classes in the annotation in the {@link InstrumentationConfiguration} list of classes not to
+ * acquire. Unfortunately, this will not work because we will not be instrumenting the class.
+ * Instead, we have to load the class bytes from the system class loader but still instrument it, we
+ * do this by overriding {@link SandboxClassLoader#getByteCode(String)} and loading the class bytes
+ * from the system class loader if it in the {@link SystemLoaderClasses} annotation. This way the
+ * {@link SandboxClassLoader} still instruments the class, but it's not loaded from the android jar.
+ * Finally, we inject the custom class loader in place of the default one.
+ *
+ * TODO: Remove this when we are using locally built android jars in the method's environment.
+ */
+public class FrameworkRobolectricTestRunner extends RobolectricTestRunner {
+ private final SandboxFactory mSandboxFactory;
+
+ public FrameworkRobolectricTestRunner(Class<?> testClass) throws InitializationError {
+ super(testClass);
+ SystemLoaderClasses annotation = testClass.getAnnotation(SystemLoaderClasses.class);
+ Class<?>[] systemLoaderClasses =
+ (annotation != null) ? annotation.value() : new Class<?>[0];
+ Set<String> systemLoaderClassNames = classesToClassNames(systemLoaderClasses);
+ mSandboxFactory = new FrameworkSandboxFactory(systemLoaderClassNames);
+ }
+
+ @Nonnull
+ @Override
+ protected SdkEnvironment getSandbox(FrameworkMethod method) {
+ // HACK: Calling super just to get SdkConfig via sandbox.getSdkConfig(), because
+ // RobolectricFrameworkMethod, the runtime class of method, is package-protected
+ SdkEnvironment sandbox = super.getSandbox(method);
+ return mSandboxFactory.getSdkEnvironment(
+ createClassLoaderConfig(method),
+ getJarResolver(),
+ sandbox.getSdkConfig());
+ }
+
+ private static class FrameworkClassLoader extends SandboxClassLoader {
+ private final Set<String> mSystemLoaderClasses;
+
+ private FrameworkClassLoader(
+ Set<String> systemLoaderClasses,
+ ClassLoader systemClassLoader,
+ InstrumentationConfiguration instrumentationConfig,
+ URL... urls) {
+ super(systemClassLoader, instrumentationConfig, urls);
+ mSystemLoaderClasses = systemLoaderClasses;
+ }
+
+ @Override
+ protected byte[] getByteCode(String className) throws ClassNotFoundException {
+ String classFileName = className.replace('.', '/') + ".class";
+ if (shouldLoadFromSystemLoader(className)) {
+ try (InputStream classByteStream = getResourceAsStream(classFileName)) {
+ if (classByteStream == null) {
+ throw new ClassNotFoundException(className);
+ }
+ return Util.readBytes(classByteStream);
+ } catch (IOException e) {
+ throw new ClassNotFoundException(
+ "Couldn't load " + className + " from system class loader", e);
+ }
+ }
+ return super.getByteCode(className);
+ }
+
+ /**
+ * Classes like com.package.ClassName$InnerClass should also be loaded from the system class
+ * loader, so we test if the classes in the annotation are prefixes of the class to load.
+ */
+ private boolean shouldLoadFromSystemLoader(String className) {
+ for (String classNamePrefix : mSystemLoaderClasses) {
+ if (className.startsWith(classNamePrefix)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private static class FrameworkSandboxFactory extends SandboxFactory {
+ private final Set<String> mSystemLoaderClasses;
+
+ private FrameworkSandboxFactory(Set<String> systemLoaderClasses) {
+ mSystemLoaderClasses = systemLoaderClasses;
+ }
+
+ @Nonnull
+ @Override
+ public ClassLoader createClassLoader(
+ InstrumentationConfiguration instrumentationConfig, URL... urls) {
+ return new FrameworkClassLoader(
+ mSystemLoaderClasses,
+ ClassLoader.getSystemClassLoader(),
+ instrumentationConfig,
+ urls);
+ }
+ }
+
+ private static Set<String> classesToClassNames(Class<?>[] classes) {
+ ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+ for (Class<?> classObject : classes) {
+ builder.add(classObject.getName());
+ }
+ return builder.build();
+ }
+}
diff --git a/services/robotests/src/com/android/server/testing/SystemLoaderClasses.java b/services/robotests/src/com/android/server/testing/SystemLoaderClasses.java
new file mode 100644
index 0000000..646a413
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/SystemLoaderClasses.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 com.android.server.testing;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to be used in test classes that run with {@link FrameworkRobolectricTestRunner}.
+ * This will make the classes specified be loaded from the system class loader, NOT from the
+ * Robolectric android jar.
+ *
+ * @see FrameworkRobolectricTestRunner
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SystemLoaderClasses {
+ Class<?>[] value() default {};
+}
diff --git a/services/tests/Android.mk b/services/tests/Android.mk
deleted file mode 100644
index 40369ee..0000000
--- a/services/tests/Android.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationTestCase.java b/services/tests/notification/src/com/android/server/notification/NotificationTestCase.java
deleted file mode 100644
index 1ee3412..0000000
--- a/services/tests/notification/src/com/android/server/notification/NotificationTestCase.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.notification;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.testing.TestableContext;
-
-import org.junit.Rule;
-
-
-public class NotificationTestCase {
- @Rule
- public final TestableContext mContext =
- new TestableContext(InstrumentationRegistry.getContext(), null);
-
- protected TestableContext getContext() {
- return mContext;
- }
-}
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index e5ab44f..218a2b8 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -38,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/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/NetworkScorerAppManagerTest.java b/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
index 82ff0d8..6874624 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
@@ -52,10 +52,10 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import org.mockito.compat.ArgumentMatcher;
import java.util.ArrayList;
import java.util.List;
@@ -82,13 +82,9 @@
MockitoAnnotations.initMocks(this);
mAvailableServices = new ArrayList<>();
when(mMockContext.getPackageManager()).thenReturn(mMockPm);
- when(mMockPm.queryIntentServices(Mockito.argThat(new ArgumentMatcher<Intent>() {
- @Override
- public boolean matchesObject(Object object) {
- Intent intent = (Intent) object;
- return NetworkScoreManager.ACTION_RECOMMEND_NETWORKS.equals(intent.getAction());
- }
- }), eq(PackageManager.GET_META_DATA))).thenReturn(mAvailableServices);
+ when(mMockPm.queryIntentServices(Mockito.argThat(
+ intent -> NetworkScoreManager.ACTION_RECOMMEND_NETWORKS.equals(intent.getAction())),
+ eq(PackageManager.GET_META_DATA))).thenReturn(mAvailableServices);
when(mMockContext.getResources()).thenReturn(mResources);
when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
@@ -664,15 +660,10 @@
final int flags = PackageManager.GET_META_DATA;
when(mMockPm.resolveService(
- Mockito.argThat(new ArgumentMatcher<Intent>() {
- @Override
- public boolean matchesObject(Object object) {
- Intent intent = (Intent) object;
- return NetworkScoreManager.ACTION_RECOMMEND_NETWORKS
- .equals(intent.getAction())
- && compName.getPackageName().equals(intent.getPackage());
- }
- }), Mockito.eq(flags))).thenReturn(serviceInfo);
+ Mockito.argThat(intent -> NetworkScoreManager.ACTION_RECOMMEND_NETWORKS
+ .equals(intent.getAction())
+ && compName.getPackageName().equals(intent.getPackage())),
+ Mockito.eq(flags))).thenReturn(serviceInfo);
mAvailableServices.add(serviceInfo);
}
@@ -685,13 +676,9 @@
final int flags = 0;
when(mMockPm.resolveActivity(
- Mockito.argThat(new ArgumentMatcher<Intent>() {
- @Override
- public boolean matchesObject(Object object) {
- Intent intent = (Intent) object;
- return NetworkScoreManager.ACTION_CUSTOM_ENABLE.equals(intent.getAction())
- && useOpenWifiComp.getPackageName().equals(intent.getPackage());
- }
- }), Mockito.eq(flags))).thenReturn(resolveActivityInfo);
+ Mockito.argThat(intent ->
+ NetworkScoreManager.ACTION_CUSTOM_ENABLE.equals(intent.getAction())
+ && useOpenWifiComp.getPackageName().equals(intent.getPackage())),
+ Mockito.eq(flags))).thenReturn(resolveActivityInfo);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
index d286b3f..6cacb1f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
@@ -65,7 +65,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-import org.mockito.compat.ArgumentMatcher;
/**
* Tests for MotionEventInjector
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..a44f5c4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
@@ -0,0 +1,107 @@
+/*
+ * 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.content.Intent;
+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).obtain();
+ }
+
+ /**
+ * Ensures that pending launches are processed.
+ */
+ @Test
+ 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));
+ }
+
+
+ /**
+ * Ensures instances are recycled after execution.
+ */
+ @Test
+ public void testRecycling() throws Exception {
+ final Intent intent = new Intent();
+ final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
+ mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
+ optionStarter
+ .setIntent(intent)
+ .setReason("Test")
+ .execute();
+ verify(mFactory, times(1)).recycle(eq(optionStarter));
+ }
+}
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 1cec0d9..589a89b 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -63,12 +63,13 @@
import static android.app.ActivityManager.START_INTENT_NOT_RESOLVED;
import com.android.internal.os.BatteryStatsImpl;
+import com.android.server.am.ActivityStarter.Factory;
/**
- * 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 +77,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 +95,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 +167,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 +178,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 +254,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,15 +268,18 @@
// 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();
}
}
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 13ca10c..0d03863 100644
--- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
@@ -479,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,
@@ -781,4 +781,4 @@
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/OverlayPackagesProviderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java
new file mode 100644
index 0000000..4447fe9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java
@@ -0,0 +1,390 @@
+/*
+ * 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.devicepolicy;
+
+import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
+import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
+import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.os.RemoteException;
+import android.support.test.InstrumentationRegistry;
+import android.test.AndroidTestCase;
+import android.test.mock.MockPackageManager;
+import android.view.inputmethod.InputMethodInfo;
+
+import com.android.internal.R;
+import com.android.internal.view.IInputMethodManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class OverlayPackagesProviderTest extends AndroidTestCase {
+ private static final String TEST_DPC_PACKAGE_NAME = "dpc.package.name";
+ private static final ComponentName TEST_MDM_COMPONENT_NAME = new ComponentName(
+ TEST_DPC_PACKAGE_NAME, "pc.package.name.DeviceAdmin");
+ private static final int TEST_USER_ID = 123;
+
+ private @Mock
+ Resources mResources;
+ private @Mock
+ IInputMethodManager mIInputMethodManager;
+ private @Mock
+ Context mTestContext;
+ private Resources mRealResources;
+
+ private FakePackageManager mPackageManager;
+ private String[] mSystemAppsWithLauncher;
+ private OverlayPackagesProvider mHelper;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mPackageManager = new FakePackageManager();
+ when(mTestContext.getResources()).thenReturn(mResources);
+ when(mTestContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mTestContext.getFilesDir()).thenReturn(
+ InstrumentationRegistry.getTargetContext().getCacheDir());
+
+ setSystemInputMethods();
+ setRequiredAppsManagedDevice();
+ setVendorRequiredAppsManagedDevice();
+ setDisallowedAppsManagedDevice();
+ setVendorDisallowedAppsManagedDevice();
+ setRequiredAppsManagedProfile();
+ setVendorRequiredAppsManagedProfile();
+ setDisallowedAppsManagedProfile();
+ setVendorDisallowedAppsManagedProfile();
+ setRequiredAppsManagedUser();
+ setVendorRequiredAppsManagedUser();
+ setDisallowedAppsManagedUser();
+ setVendorDisallowedAppsManagedUser();
+
+ mRealResources = InstrumentationRegistry.getTargetContext().getResources();
+ mHelper = new OverlayPackagesProvider(mTestContext, mIInputMethodManager);
+ }
+
+ @Test
+ public void testAppsWithLauncherAreNonRequiredByDefault() {
+ setSystemAppsWithLauncher("app.a", "app.b");
+
+ verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_DEVICE, "app.a", "app.b");
+ }
+
+ @Test
+ public void testDeviceOwnerRequiredApps() {
+ setSystemAppsWithLauncher("app.a", "app.b", "app.c");
+ setRequiredAppsManagedDevice("app.a");
+ setVendorRequiredAppsManagedDevice("app.b");
+
+ verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_DEVICE, "app.c");
+ }
+
+ @Test
+ public void testProfileOwnerRequiredApps() {
+ setSystemAppsWithLauncher("app.a", "app.b", "app.c");
+ setRequiredAppsManagedProfile("app.a");
+ setVendorRequiredAppsManagedProfile("app.b");
+
+ verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_PROFILE, "app.c");
+ }
+
+ @Test
+ public void testManagedUserRequiredApps() {
+ setSystemAppsWithLauncher("app.a", "app.b", "app.c");
+ setRequiredAppsManagedUser("app.a");
+ setVendorRequiredAppsManagedUser("app.b");
+
+ verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_USER, "app.c");
+ }
+
+ @Test
+ public void testDpcIsRequired() {
+ setSystemAppsWithLauncher("app.a", TEST_DPC_PACKAGE_NAME);
+
+ verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_DEVICE, "app.a");
+ }
+
+ @Test
+ public void testDisallowedAppsAreNonRequiredEvenIfNoLauncher() {
+ setSystemAppsWithLauncher();
+ setDisallowedAppsManagedDevice("app.a");
+ setVendorDisallowedAppsManagedDevice("app.b");
+
+ verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_DEVICE, "app.a", "app.b");
+ }
+
+ @Test
+ public void testDeviceOwnerImesAreRequired() {
+ setSystemAppsWithLauncher("app.a", "app.b");
+ setSystemInputMethods("app.a");
+
+ verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_DEVICE, "app.b");
+ }
+
+ @Test
+ public void testProfileOwnerImesAreNonRequired() {
+ setSystemAppsWithLauncher("app.a", "app.b");
+ setSystemInputMethods("app.a");
+
+ verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_PROFILE, "app.a", "app.b");
+ }
+
+ @Test
+ public void testManagedUserImesAreRequired() {
+ setSystemAppsWithLauncher("app.a", "app.b");
+ setSystemInputMethods("app.a");
+
+ verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_USER, "app.b");
+ }
+
+ @Test
+ public void testDisallowedAppsAreNonInstalled() {
+ setSystemAppsWithLauncher("app.a");
+ setDisallowedAppsManagedDevice("app.c");
+
+ verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_DEVICE, "app.a", "app.c");
+ }
+
+ /**
+ * If an app is listed as both required and disallowed, it should be only in the disallowed
+ * list. Therefore, it should be present in the non-required list.
+ */
+ @Test
+ public void testAllowedAndDisallowedAtTheSameTimeManagedDevice() {
+ setDisallowedAppsManagedDevice(TEST_DPC_PACKAGE_NAME);
+ setRequiredAppsManagedDevice(TEST_DPC_PACKAGE_NAME);
+
+ verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_DEVICE, TEST_DPC_PACKAGE_NAME);
+ }
+
+ /**
+ * @see {@link #testAllowedAndDisallowedAtTheSameTimeManagedDevice}
+ */
+ @Test
+ public void testAllowedAndDisallowedAtTheSameTimeManagedUser() {
+ setDisallowedAppsManagedUser(TEST_DPC_PACKAGE_NAME);
+ setRequiredAppsManagedUser(TEST_DPC_PACKAGE_NAME);
+
+ verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_USER, TEST_DPC_PACKAGE_NAME);
+ }
+
+ /**
+ * @see {@link #testAllowedAndDisallowedAtTheSameTimeManagedDevice}
+ */
+ @Test
+ public void testAllowedAndDisallowedAtTheSameTimeManagedProfile() {
+ setDisallowedAppsManagedProfile(TEST_DPC_PACKAGE_NAME);
+ setRequiredAppsManagedProfile(TEST_DPC_PACKAGE_NAME);
+
+ verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_PROFILE, TEST_DPC_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testNotRequiredAndDisallowedInResManagedDevice() {
+ verifyEmptyIntersection(R.array.required_apps_managed_device,
+ R.array.disallowed_apps_managed_device);
+ }
+
+ @Test
+ public void testNotRequiredAndDisallowedInResManagedUser() {
+ verifyEmptyIntersection(R.array.required_apps_managed_user,
+ R.array.disallowed_apps_managed_user);
+ }
+
+ @Test
+ public void testNotRequiredAndDisallowedInResManagedProfile() {
+ verifyEmptyIntersection(R.array.required_apps_managed_profile,
+ R.array.disallowed_apps_managed_profile);
+ }
+
+ @Test
+ public void testNotRequiredAndDisallowedInResManagedDeviceVendor() {
+ verifyEmptyIntersection(R.array.vendor_required_apps_managed_device,
+ R.array.vendor_disallowed_apps_managed_device);
+ }
+
+ @Test
+ public void testNotRequiredAndDisallowedInResManagedUserVendor() {
+ verifyEmptyIntersection(R.array.vendor_required_apps_managed_user,
+ R.array.vendor_disallowed_apps_managed_user);
+ }
+
+ @Test
+ public void testNotRequiredAndDisallowedInResManagedProfileVendor() {
+ verifyEmptyIntersection(R.array.vendor_required_apps_managed_profile,
+ R.array.vendor_disallowed_apps_managed_profile);
+ }
+
+ private ArrayList<String> getStringArrayInRealResources(int id) {
+ return new ArrayList<>(Arrays.asList(mRealResources.getStringArray(id)));
+ }
+
+ private void verifyEmptyIntersection(int requiredId, int disallowedId) {
+ ArrayList<String> required = getStringArrayInRealResources(requiredId);
+ ArrayList<String> disallowed = getStringArrayInRealResources(disallowedId);
+ required.retainAll(disallowed);
+ assertTrue(required.isEmpty());
+ }
+
+ private void verifyAppsAreNonRequired(String action, String... appArray) {
+ assertEquals(listFromArray(appArray),
+ mHelper.getNonRequiredApps(TEST_MDM_COMPONENT_NAME, TEST_USER_ID, action));
+ }
+
+ private void setRequiredAppsManagedDevice(String... apps) {
+ setStringArray(R.array.required_apps_managed_device, apps);
+ }
+
+ private void setVendorRequiredAppsManagedDevice(String... apps) {
+ setStringArray(R.array.vendor_required_apps_managed_device, apps);
+ }
+
+ private void setDisallowedAppsManagedDevice(String... apps) {
+ setStringArray(R.array.disallowed_apps_managed_device, apps);
+ }
+
+ private void setVendorDisallowedAppsManagedDevice(String... apps) {
+ setStringArray(R.array.vendor_disallowed_apps_managed_device, apps);
+ }
+
+ private void setRequiredAppsManagedProfile(String... apps) {
+ setStringArray(R.array.required_apps_managed_profile, apps);
+ }
+
+ private void setVendorRequiredAppsManagedProfile(String... apps) {
+ setStringArray(R.array.vendor_required_apps_managed_profile, apps);
+ }
+
+ private void setDisallowedAppsManagedProfile(String... apps) {
+ setStringArray(R.array.disallowed_apps_managed_profile, apps);
+ }
+
+ private void setVendorDisallowedAppsManagedProfile(String... apps) {
+ setStringArray(R.array.vendor_disallowed_apps_managed_profile, apps);
+ }
+
+ private void setRequiredAppsManagedUser(String... apps) {
+ setStringArray(R.array.required_apps_managed_user, apps);
+ }
+
+ private void setVendorRequiredAppsManagedUser(String... apps) {
+ setStringArray(R.array.vendor_required_apps_managed_user, apps);
+ }
+
+ private void setDisallowedAppsManagedUser(String... apps) {
+ setStringArray(R.array.disallowed_apps_managed_user, apps);
+ }
+
+ private void setVendorDisallowedAppsManagedUser(String... apps) {
+ setStringArray(R.array.vendor_disallowed_apps_managed_user, apps);
+ }
+
+ private void setStringArray(int resourceId, String[] strs) {
+ when(mResources.getStringArray(eq(resourceId)))
+ .thenReturn(strs);
+ }
+
+ private void setSystemInputMethods(String... packageNames) {
+ List<InputMethodInfo> inputMethods = new ArrayList<InputMethodInfo>();
+ for (String packageName : packageNames) {
+ ApplicationInfo aInfo = new ApplicationInfo();
+ aInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+ ServiceInfo serviceInfo = new ServiceInfo();
+ serviceInfo.applicationInfo = aInfo;
+ serviceInfo.packageName = packageName;
+ serviceInfo.name = "";
+ ResolveInfo ri = new ResolveInfo();
+ ri.serviceInfo = serviceInfo;
+ InputMethodInfo inputMethodInfo = new InputMethodInfo(ri, false, null, null, 0, false);
+ inputMethods.add(inputMethodInfo);
+ }
+ try {
+ when(mIInputMethodManager.getInputMethodList()).thenReturn(inputMethods);
+ } catch (RemoteException e) {
+ fail(e.toString());
+ }
+ }
+
+ private void setSystemAppsWithLauncher(String... apps) {
+ mSystemAppsWithLauncher = apps;
+ }
+
+ private <T> Set<T> setFromArray(T... array) {
+ if (array == null) {
+ return null;
+ }
+ return new HashSet<T>(Arrays.asList(array));
+ }
+
+ private <T> List<T> listFromArray(T... array) {
+ if (array == null) {
+ return null;
+ }
+ return Arrays.asList(array);
+ }
+
+ class FakePackageManager extends MockPackageManager {
+ @Override
+ public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int flags, int userId) {
+ assertTrue("Expected an intent with action ACTION_MAIN",
+ Intent.ACTION_MAIN.equals(intent.getAction()));
+ assertEquals("Expected an intent with category CATEGORY_LAUNCHER",
+ setFromArray(Intent.CATEGORY_LAUNCHER), intent.getCategories());
+ assertTrue("Expected the flag MATCH_UNINSTALLED_PACKAGES",
+ (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0);
+ assertTrue("Expected the flag MATCH_DISABLED_COMPONENTS",
+ (flags & PackageManager.MATCH_DISABLED_COMPONENTS) != 0);
+ assertTrue("Expected the flag MATCH_DIRECT_BOOT_AWARE",
+ (flags & PackageManager.MATCH_DIRECT_BOOT_AWARE) != 0);
+ assertTrue("Expected the flag MATCH_DIRECT_BOOT_UNAWARE",
+ (flags & PackageManager.MATCH_DIRECT_BOOT_UNAWARE) != 0);
+ assertEquals(userId, TEST_USER_ID);
+ List<ResolveInfo> result = new ArrayList<>();
+ if (mSystemAppsWithLauncher == null) {
+ return result;
+ }
+ for (String packageName : mSystemAppsWithLauncher) {
+ ActivityInfo ai = new ActivityInfo();
+ ai.packageName = packageName;
+ ResolveInfo ri = new ResolveInfo();
+ ri.activityInfo = ai;
+ result.add(ri);
+ }
+ return result;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
new file mode 100644
index 0000000..2629b12
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -0,0 +1,230 @@
+/*
+ * 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.display;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.os.PowerManager;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Spline;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BrightnessMappingStrategyTest {
+
+ private static final float[] LUX_LEVELS = {
+ 0f,
+ 5f,
+ 20f,
+ 40f,
+ 100f,
+ 325f,
+ 600f,
+ 1250f,
+ 2200f,
+ 4000f,
+ 5000f
+ };
+
+ private static final float[] DISPLAY_LEVELS_NITS = {
+ 13.25f,
+ 54.0f,
+ 78.85f,
+ 105.02f,
+ 132.7f,
+ 170.12f,
+ 212.1f,
+ 265.2f,
+ 335.8f,
+ 415.2f,
+ 478.5f,
+ };
+
+ private static final int[] DISPLAY_LEVELS_BACKLIGHT = {
+ 9,
+ 30,
+ 45,
+ 62,
+ 78,
+ 96,
+ 119,
+ 146,
+ 178,
+ 221,
+ 255
+ };
+
+ private static final float[] DISPLAY_RANGE_NITS = { 2.685f, 478.5f };
+ private static final int[] BACKLIGHT_RANGE = { 1, 255 };
+
+ @Test
+ public void testSimpleStrategyMappingAtControlPoints() {
+ BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(
+ LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT,
+ null /*brightnessLevelsNits*/, null /*nitsRange*/, null /*backlightRange*/);
+ assertNotNull("BrightnessMappingStrategy should not be null", simple);
+ for (int i = 0; i < LUX_LEVELS.length; i++) {
+ final float expectedLevel =
+ (float) DISPLAY_LEVELS_BACKLIGHT[i] / PowerManager.BRIGHTNESS_ON;
+ assertEquals(expectedLevel,
+ simple.getBrightness(LUX_LEVELS[i]), 0.01f /*tolerance*/);
+ }
+ }
+
+ @Test
+ public void testSimpleStrategyMappingBetweenControlPoints() {
+ BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(
+ LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT,
+ null /*brightnessLevelsNits*/, null /*nitsRange*/, null /*backlightRange*/);
+ assertNotNull("BrightnessMappingStrategy should not be null", simple);
+ for (int i = 1; i < LUX_LEVELS.length; i++) {
+ final float lux = (LUX_LEVELS[i - 1] + LUX_LEVELS[i]) / 2;
+ final float backlight = simple.getBrightness(lux) * PowerManager.BRIGHTNESS_ON;
+ assertTrue("Desired brightness should be between adjacent control points.",
+ backlight > DISPLAY_LEVELS_BACKLIGHT[i-1]
+ && backlight < DISPLAY_LEVELS_BACKLIGHT[i]);
+ }
+ }
+
+ @Test
+ public void testPhysicalStrategyMappingAtControlPoints() {
+ BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(
+ LUX_LEVELS, null /*brightnessLevelsBacklight*/,
+ DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ assertNotNull("BrightnessMappingStrategy should not be null", physical);
+ for (int i = 0; i < LUX_LEVELS.length; i++) {
+ final float expectedLevel = DISPLAY_LEVELS_NITS[i] / DISPLAY_RANGE_NITS[1];
+ assertEquals(expectedLevel,
+ physical.getBrightness(LUX_LEVELS[i]), 0.01f /*tolerance*/);
+ }
+ }
+
+ @Test
+ public void testPhysicalStrategyMappingBetweenControlPoints() {
+ BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(
+ LUX_LEVELS, null /*brightnessLevelsBacklight*/,
+ DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ assertNotNull("BrightnessMappingStrategy should not be null", physical);
+ Spline backlightToBrightness =
+ Spline.createSpline(toFloatArray(BACKLIGHT_RANGE), DISPLAY_RANGE_NITS);
+ for (int i = 1; i < LUX_LEVELS.length; i++) {
+ final float lux = (LUX_LEVELS[i - 1] + LUX_LEVELS[i]) / 2;
+ final float backlight = physical.getBrightness(lux) * PowerManager.BRIGHTNESS_ON;
+ final float nits = backlightToBrightness.interpolate(backlight);
+ assertTrue("Desired brightness should be between adjacent control points.",
+ nits > DISPLAY_LEVELS_NITS[i-1] && nits < DISPLAY_LEVELS_NITS[i]);
+ }
+ }
+
+ @Test
+ public void testDefaultStrategyIsPhysical() {
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(
+ LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT,
+ DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ assertTrue(strategy instanceof BrightnessMappingStrategy.PhysicalMappingStrategy);
+ }
+
+ @Test
+ public void testNonStrictlyIncreasingLuxLevelsFails() {
+ final float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length);
+ final int idx = lux.length / 2;
+ float tmp = lux[idx];
+ lux[idx] = lux[idx+1];
+ lux[idx+1] = tmp;
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(
+ lux, null /*brightnessLevelsBacklight*/,
+ DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ assertNull(strategy);
+
+ // And make sure we get the same result even if it's monotone but not increasing.
+ lux[idx] = lux[idx+1];
+ strategy = BrightnessMappingStrategy.create(
+ lux, null /*brightnessLevelsBacklight*/,
+ DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ assertNull(strategy);
+ }
+
+ @Test
+ public void testDifferentNumberOfControlPointValuesFails() {
+ //Extra lux level
+ final float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length+1);
+ // Make sure it's strictly increasing so that the only failure is the differing array
+ // lengths
+ lux[lux.length - 1] = lux[lux.length - 2] + 1;
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(
+ lux, null /*brightnessLevelsBacklight*/,
+ DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ assertNull(strategy);
+
+ strategy = BrightnessMappingStrategy.create(
+ lux, DISPLAY_LEVELS_BACKLIGHT,
+ null /*brightnessLevelsNits*/, null /*nitsRange*/, null /*backlightRange*/);
+ assertNull(strategy);
+
+ // Extra backlight level
+ final int[] backlight = Arrays.copyOf(
+ DISPLAY_LEVELS_BACKLIGHT, DISPLAY_LEVELS_BACKLIGHT.length+1);
+ backlight[backlight.length - 1] = backlight[backlight.length - 2] + 1;
+ strategy = BrightnessMappingStrategy.create(
+ LUX_LEVELS, backlight,
+ null /*brightnessLevelsNits*/, null /*nitsRange*/, null /*backlightRange*/);
+ assertNull(strategy);
+
+ // Extra nits level
+ final float[] nits = Arrays.copyOf(DISPLAY_RANGE_NITS, DISPLAY_LEVELS_NITS.length+1);
+ nits[nits.length - 1] = nits[nits.length - 2] + 1;
+ strategy = BrightnessMappingStrategy.create(
+ LUX_LEVELS, null /*brightnessLevelsBacklight*/,
+ nits, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ assertNull(strategy);
+ }
+
+ @Test
+ public void testPhysicalStrategyRequiresNitsMapping() {
+ BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(
+ LUX_LEVELS, null /*brightnessLevelsBacklight*/,
+ DISPLAY_LEVELS_NITS, null, BACKLIGHT_RANGE);
+ assertNull(physical);
+
+ physical = BrightnessMappingStrategy.create(
+ LUX_LEVELS, null /*brightnessLevelsBacklight*/,
+ DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, null);
+ assertNull(physical);
+
+ physical = BrightnessMappingStrategy.create(
+ LUX_LEVELS, null /*brightnessLevelsBacklight*/,
+ DISPLAY_LEVELS_NITS, null, null);
+ assertNull(physical);
+ }
+
+ private static float[] toFloatArray(int[] vals) {
+ float[] newVals = new float[vals.length];
+ for (int i = 0; i < vals.length; i++) {
+ newVals[i] = (float) vals[i];
+ }
+ return newVals;
+ }
+}
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/display/PersistentDataStoreTest.java b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
new file mode 100644
index 0000000..0cc37b4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
@@ -0,0 +1,223 @@
+/*
+ * 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.display;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.hardware.display.BrightnessConfiguration;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.AtomicFile;
+import android.util.Pair;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PersistentDataStoreTest {
+ private PersistentDataStore mDataStore;
+ private TestInjector mInjector;
+
+ @Before
+ public void setUp() {
+ mInjector = new TestInjector();
+ mDataStore = new PersistentDataStore(mInjector);
+ }
+
+ @Test
+ public void testLoadingBrightnessConfigurations() {
+ String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<display-manager-state>\n"
+ + " <brightness-configurations>\n"
+ + " <brightness-configuration user-serial=\"1\">\n"
+ + " <brightness-curve>\n"
+ + " <brightness-point lux=\"0\" nits=\"13.25\"/>\n"
+ + " <brightness-point lux=\"25\" nits=\"35.94\"/>\n"
+ + " </brightness-curve>\n"
+ + " </brightness-configuration>\n"
+ + " <brightness-configuration user-serial=\"3\">\n"
+ + " <brightness-curve>\n"
+ + " <brightness-point lux=\"0\" nits=\"13.25\"/>\n"
+ + " <brightness-point lux=\"10.2\" nits=\"15\"/>\n"
+ + " </brightness-curve>\n"
+ + " </brightness-configuration>\n"
+ + " </brightness-configurations>\n"
+ + "</display-manager-state>\n";
+ InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
+ mInjector.setReadStream(is);
+ mDataStore.loadIfNeeded();
+ BrightnessConfiguration config = mDataStore.getBrightnessConfiguration(1 /*userSerial*/);
+ Pair<float[], float[]> curve = config.getCurve();
+ float[] expectedLux = { 0f, 25f };
+ float[] expectedNits = { 13.25f, 35.94f };
+ assertArrayEquals(expectedLux, curve.first, "lux");
+ assertArrayEquals(expectedNits, curve.second, "nits");
+
+ config = mDataStore.getBrightnessConfiguration(3 /*userSerial*/);
+ curve = config.getCurve();
+ expectedLux = new float[] { 0f, 10.2f };
+ expectedNits = new float[] { 13.25f, 15f };
+ assertArrayEquals(expectedLux, curve.first, "lux");
+ assertArrayEquals(expectedNits, curve.second, "nits");
+ }
+
+ @Test
+ public void testBrightnessConfigWithInvalidCurveIsIgnored() {
+ String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<display-manager-state>\n"
+ + " <brightness-configurations>\n"
+ + " <brightness-configuration user-serial=\"0\">\n"
+ + " <brightness-curve>\n"
+ + " <brightness-point lux=\"1\" nits=\"13.25\"/>\n"
+ + " <brightness-point lux=\"25\" nits=\"35.94\"/>\n"
+ + " </brightness-curve>\n"
+ + " </brightness-configuration>\n"
+ + " </brightness-configurations>\n"
+ + "</display-manager-state>\n";
+ InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
+ mInjector.setReadStream(is);
+ mDataStore.loadIfNeeded();
+ assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/));
+ }
+
+ @Test
+ public void testBrightnessConfigWithInvalidFloatsIsIgnored() {
+ String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<display-manager-state>\n"
+ + " <brightness-configurations>\n"
+ + " <brightness-configuration user-serial=\"0\">\n"
+ + " <brightness-curve>\n"
+ + " <brightness-point lux=\"0\" nits=\"13.25\"/>\n"
+ + " <brightness-point lux=\"0xFF\" nits=\"foo\"/>\n"
+ + " </brightness-curve>\n"
+ + " </brightness-configuration>\n"
+ + " </brightness-configurations>\n"
+ + "</display-manager-state>\n";
+ InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
+ mInjector.setReadStream(is);
+ mDataStore.loadIfNeeded();
+ assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/));
+ }
+
+ @Test
+ public void testEmptyBrightnessConfigurationsDoesntCrash() {
+ String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<display-manager-state>\n"
+ + " <brightness-configurations />\n"
+ + "</display-manager-state>\n";
+ InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
+ mInjector.setReadStream(is);
+ mDataStore.loadIfNeeded();
+ assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/));
+ }
+
+ @Test
+ public void testStoreAndReloadOfBrightnessConfigurations() {
+ final float[] lux = { 0f, 10f };
+ final float[] nits = {1f, 100f };
+ final BrightnessConfiguration config = new BrightnessConfiguration.Builder()
+ .setCurve(lux, nits)
+ .build();
+ mDataStore.loadIfNeeded();
+ assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/));
+ mDataStore.setBrightnessConfigurationForUser(config, 0);
+
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ mInjector.setWriteStream(baos);
+ mDataStore.saveIfNeeded();
+ assertTrue(mInjector.wasWriteSuccessful());
+
+ TestInjector newInjector = new TestInjector();
+ PersistentDataStore newDataStore = new PersistentDataStore(newInjector);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ newInjector.setReadStream(bais);
+ newDataStore.loadIfNeeded();
+ assertNotNull(newDataStore.getBrightnessConfiguration(0 /*userSerial*/));
+ assertEquals(mDataStore.getBrightnessConfiguration(0 /*userSerial*/),
+ newDataStore.getBrightnessConfiguration(0 /*userSerial*/));
+ }
+
+ public class TestInjector extends PersistentDataStore.Injector {
+ private InputStream mReadStream;
+ private OutputStream mWriteStream;
+
+ private boolean mWasSuccessful;
+
+ @Override
+ public InputStream openRead() throws FileNotFoundException {
+ if (mReadStream != null) {
+ return mReadStream;
+ } else {
+ throw new FileNotFoundException();
+ }
+ }
+
+ @Override
+ public OutputStream startWrite() {
+ return mWriteStream;
+ }
+
+ @Override
+ public void finishWrite(OutputStream os, boolean success) {
+ mWasSuccessful = success;
+ try {
+ os.close();
+ } catch (IOException e) {
+ // This method can't throw IOException since the super implementation doesn't, so
+ // we just wrap it in a RuntimeException so we end up crashing the test all the
+ // same.
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void setReadStream(InputStream is) {
+ mReadStream = is;
+ }
+
+ public void setWriteStream(OutputStream os) {
+ mWriteStream = os;
+ }
+
+ public boolean wasWriteSuccessful() {
+ return mWasSuccessful;
+ }
+ }
+
+ private static void assertArrayEquals(float[] expected, float[] actual, String name) {
+ assertEquals("Expected " + name + " arrays to be the same length!",
+ expected.length, actual.length);
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals("Expected " + name + " arrays to be equivalent when value " + i
+ + "differs", expected[i], actual[i], 0.01 /*tolerance*/);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
new file mode 100644
index 0000000..298a988
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.locksettings.recoverablekeystore;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.security.keystore.AndroidKeyStoreSecretKey;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.security.KeyStore;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RecoverableKeyGeneratorTest {
+ private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
+ private static final String KEY_ALGORITHM = "AES";
+ private static final String TEST_ALIAS = "karlin";
+ private static final String WRAPPING_KEY_ALIAS = "RecoverableKeyGeneratorTestWrappingKey";
+
+ @Mock
+ RecoverableKeyStorage mRecoverableKeyStorage;
+
+ @Captor ArgumentCaptor<KeyProtection> mKeyProtectionArgumentCaptor;
+
+ private AndroidKeyStoreSecretKey mPlatformKey;
+ private SecretKey mKeyHandle;
+ private RecoverableKeyGenerator mRecoverableKeyGenerator;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mPlatformKey = generateAndroidKeyStoreKey();
+ mKeyHandle = generateKey();
+ mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(
+ mPlatformKey, mRecoverableKeyStorage);
+
+ when(mRecoverableKeyStorage.loadFromAndroidKeyStore(any())).thenReturn(mKeyHandle);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
+ keyStore.load(/*param=*/ null);
+ keyStore.deleteEntry(WRAPPING_KEY_ALIAS);
+ }
+
+ @Test
+ public void generateAndStoreKey_setsKeyInKeyStore() throws Exception {
+ mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+ verify(mRecoverableKeyStorage, times(1))
+ .importIntoAndroidKeyStore(eq(TEST_ALIAS), any(), any());
+ }
+
+ @Test
+ public void generateAndStoreKey_storesKeyEnabledForEncryptDecrypt() throws Exception {
+ mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+ KeyProtection keyProtection = getKeyProtectionUsed();
+ assertEquals(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT,
+ keyProtection.getPurposes());
+ }
+
+ @Test
+ public void generateAndStoreKey_storesKeyEnabledForGCM() throws Exception {
+ mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+ KeyProtection keyProtection = getKeyProtectionUsed();
+ assertArrayEquals(new String[] { KeyProperties.BLOCK_MODE_GCM },
+ keyProtection.getBlockModes());
+ }
+
+ @Test
+ public void generateAndStoreKey_storesKeyEnabledForNoPadding() throws Exception {
+ mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+ KeyProtection keyProtection = getKeyProtectionUsed();
+ assertArrayEquals(new String[] { KeyProperties.ENCRYPTION_PADDING_NONE },
+ keyProtection.getEncryptionPaddings());
+ }
+
+ @Test
+ public void generateAndStoreKey_storesWrappedKey() throws Exception {
+ mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+ verify(mRecoverableKeyStorage, times(1)).persistToDisk(eq(TEST_ALIAS), any());
+ }
+
+ @Test
+ public void generateAndStoreKey_returnsKeyHandle() throws Exception {
+ SecretKey secretKey = mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+ assertEquals(mKeyHandle, secretKey);
+ }
+
+ private KeyProtection getKeyProtectionUsed() throws Exception {
+ verify(mRecoverableKeyStorage, times(1)).importIntoAndroidKeyStore(
+ any(), any(), mKeyProtectionArgumentCaptor.capture());
+ return mKeyProtectionArgumentCaptor.getValue();
+ }
+
+ private SecretKey generateKey() throws Exception {
+ KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
+ keyGenerator.init(/*keySize=*/ 256);
+ return keyGenerator.generateKey();
+ }
+
+ private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception {
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(
+ KEY_ALGORITHM,
+ ANDROID_KEY_STORE_PROVIDER);
+ keyGenerator.init(new KeyGenParameterSpec.Builder(
+ WRAPPING_KEY_ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .build());
+ return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java
new file mode 100644
index 0000000..4cd5631
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.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 com.android.server.locksettings.recoverablekeystore;
+
+import static org.junit.Assert.assertEquals;
+
+import android.security.keystore.AndroidKeyStoreSecretKey;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.security.KeyStore;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WrappedKeyTest {
+ private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
+ private static final String KEY_ALGORITHM = "AES";
+ private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
+ private static final String WRAPPING_KEY_ALIAS = "WrappedKeyTestWrappingKeyAlias";
+ private static final int GCM_TAG_LENGTH_BYTES = 16;
+ private static final int BITS_PER_BYTE = 8;
+ private static final int GCM_TAG_LENGTH_BITS = GCM_TAG_LENGTH_BYTES * BITS_PER_BYTE;
+
+ @After
+ public void tearDown() throws Exception {
+ KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
+ keyStore.load(/*param=*/ null);
+ keyStore.deleteEntry(WRAPPING_KEY_ALIAS);
+ }
+
+ @Test
+ public void fromSecretKey_createsWrappedKeyThatCanBeUnwrapped() throws Exception {
+ SecretKey wrappingKey = generateAndroidKeyStoreKey();
+ SecretKey rawKey = generateKey();
+
+ WrappedKey wrappedKey = WrappedKey.fromSecretKey(wrappingKey, rawKey);
+
+ Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+ cipher.init(
+ Cipher.UNWRAP_MODE,
+ wrappingKey,
+ new GCMParameterSpec(GCM_TAG_LENGTH_BITS, wrappedKey.getNonce()));
+ SecretKey unwrappedKey = (SecretKey) cipher.unwrap(
+ wrappedKey.getKeyMaterial(), KEY_ALGORITHM, Cipher.SECRET_KEY);
+ assertEquals(rawKey, unwrappedKey);
+ }
+
+ private SecretKey generateKey() throws Exception {
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
+ keyGenerator.init(/*keySize=*/ 256);
+ return keyGenerator.generateKey();
+ }
+
+ private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception {
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(
+ KEY_ALGORITHM,
+ ANDROID_KEY_STORE_PROVIDER);
+ keyGenerator.init(new KeyGenParameterSpec.Builder(
+ WRAPPING_KEY_ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .build());
+ return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
+ }
+}
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/InstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java
index 3fd1d55..b2eb572 100644
--- a/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java
@@ -16,19 +16,28 @@
package com.android.server.pm;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageStats;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
import com.android.internal.util.ArrayUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.Arrays;
-public class InstallerTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class InstallerTest {
private static final String TAG = "InstallerTest";
private Installer mInstaller;
@@ -64,7 +73,7 @@
}
}
- @Override
+ @Before
public void setUp() throws Exception {
mInstaller = new Installer(getContext());
mInstaller.onStart();
@@ -72,13 +81,15 @@
mQuota.reset();
}
- @Override
+ @After
public void tearDown() throws Exception {
Log.i(TAG, mManual.toString());
Log.i(TAG, mQuota.toString());
mInstaller = null;
}
+ @Test
+ @Ignore("b/68819006")
public void testGetAppSize() throws Exception {
int[] appIds = null;
@@ -119,6 +130,8 @@
}
}
+ @Test
+ @Ignore("b/68819006")
public void testGetUserSize() throws Exception {
final int[] appIds = getAppIds(UserHandle.USER_SYSTEM);
@@ -138,6 +151,8 @@
checkEquals(Arrays.toString(appIds), stats, quotaStats);
}
+ @Test
+ @Ignore("b/68819006")
public void testGetExternalSize() throws Exception {
final int[] appIds = getAppIds(UserHandle.USER_SYSTEM);
@@ -167,6 +182,10 @@
return appIds;
}
+ private static Context getContext() {
+ return InstrumentationRegistry.getContext();
+ }
+
private static void checkEquals(String msg, PackageStats a, PackageStats b) {
checkEquals(msg + " codeSize", a.codeSize, b.codeSize);
checkEquals(msg + " dataSize", a.dataSize, b.dataSize);
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/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index beffcee..e12a8da 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -43,11 +43,13 @@
class PackageSenderImpl implements PackageSender {
public void sendPackageBroadcast(final String action, final String pkg,
final Bundle extras, final int flags, final String targetPkg,
- final IIntentReceiver finishedReceiver, final int[] userIds) {
+ final IIntentReceiver finishedReceiver, final int[] userIds,
+ int[] instantUserIds) {
}
public void sendPackageAddedForNewUsers(String packageName,
- boolean sendBootComplete, boolean includeStopped, int appId, int... userIds) {
+ boolean sendBootComplete, boolean includeStopped, int appId,
+ int[] userIds, int[] instantUserIds) {
}
}
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..fafae6c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -206,8 +206,8 @@
new File(InstrumentationRegistry.getContext().getFilesDir(), "com.android.bar-1");
private static final File UPDATED_CODE_PATH =
new File(InstrumentationRegistry.getContext().getFilesDir(), "com.android.bar-2");
- private static final int INITIAL_VERSION_CODE = 10023;
- private static final int UPDATED_VERSION_CODE = 10025;
+ private static final long INITIAL_VERSION_CODE = 10023L;
+ private static final long UPDATED_VERSION_CODE = 10025L;
@Test
public void testPackageStateCopy01() {
@@ -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..32b0b26 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");
@@ -520,6 +520,10 @@
pkg.featureGroups = new ArrayList<>();
pkg.featureGroups.add(new FeatureGroupInfo());
+
+ pkg.mCompileSdkVersionCodename = "foo23";
+ pkg.mCompileSdkVersion = 100;
+ pkg.mVersionCodeMajor = 100;
}
private static void assertAllFieldsExist(PackageParser.Package pkg) throws Exception {
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..2257960f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -121,6 +121,8 @@
@SmallTest
public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
+ private static final boolean SKIP_FOR_BUG_67325252 = true;
+
/**
* Test for the first launch path, no settings file available.
*/
@@ -722,6 +724,10 @@
}
public void testCleanupDanglingBitmaps() throws Exception {
+ if (SKIP_FOR_BUG_67325252) {
+ return;
+ }
+
assertBitmapDirectories(USER_0, EMPTY_STRINGS);
assertBitmapDirectories(USER_10, EMPTY_STRINGS);
@@ -7912,4 +7918,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
index a70441d..d1e0132 100644
--- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
+++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
@@ -20,6 +20,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.IApplicationToken;
import android.view.WindowManager;
@@ -34,6 +35,8 @@
public final Rect stableFrame = new Rect();
public Rect outsetFrame = new Rect();
+ public DisplayCutout displayCutout;
+
public WindowManager.LayoutParams attrs;
public int displayId;
public boolean isVoiceInteraction;
@@ -56,7 +59,7 @@
@Override
public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overlayFrame,
Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame,
- @Nullable Rect outsetFrame) {
+ @Nullable Rect outsetFrame, DisplayCutout displayCutout) {
this.parentFrame.set(parentFrame);
this.displayFrame.set(displayFrame);
this.overscanFrame.set(overlayFrame);
@@ -65,6 +68,7 @@
this.decorFrame.set(decorFrame);
this.stableFrame.set(stableFrame);
this.outsetFrame = outsetFrame == null ? null : new Rect(outsetFrame);
+ this.displayCutout = displayCutout;
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
index 0941d4f..9a6da0e 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
@@ -16,7 +16,12 @@
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;
@@ -29,6 +34,7 @@
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;
@@ -105,4 +111,123 @@
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
index 9c55707..e7e9abad 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
@@ -17,6 +17,9 @@
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;
@@ -54,6 +57,7 @@
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;
@@ -76,10 +80,17 @@
mPolicy = TestablePhoneWindowManager.create(mContext);
+ setRotation(ROTATION_0);
+ }
+
+ public void setRotation(int rotation) {
DisplayInfo info = new DisplayInfo();
- info.logicalWidth = DISPLAY_WIDTH;
- info.logicalHeight = DISPLAY_HEIGHT;
- info.rotation = ROTATION_0;
+
+ 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);
}
@@ -95,7 +106,7 @@
public void addNavigationBar() {
mNavigationBar = new FakeWindowState();
- mNavigationBar.attrs = new WindowManager.LayoutParams(MATCH_PARENT, STATUS_BAR_HEIGHT,
+ mNavigationBar.attrs = new WindowManager.LayoutParams(MATCH_PARENT, NAV_BAR_HEIGHT,
TYPE_NAVIGATION_BAR, 0 /* flags */, PixelFormat.TRANSLUCENT);
mNavigationBar.attrs.gravity = Gravity.BOTTOM;
@@ -104,11 +115,16 @@
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,
- DISPLAY_WIDTH - expectedInsetRight, DISPLAY_HEIGHT - expectedInsetBottom), actual);
+ mFrames.mDisplayWidth - expectedInsetRight,
+ mFrames.mDisplayHeight - expectedInsetBottom), actual);
}
/**
@@ -181,6 +197,11 @@
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/timezone/PackageStatusStorageTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageStatusStorageTest.java
index b57cac0..74013b7 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/PackageStatusStorageTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/PackageStatusStorageTest.java
@@ -25,6 +25,7 @@
import android.support.test.filters.SmallTest;
import java.io.File;
+import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -33,6 +34,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
@SmallTest
public class PackageStatusStorageTest {
@@ -48,6 +50,7 @@
// Using the instrumentation context means the database is created in a test app-specific
// directory.
mPackageStatusStorage = new PackageStatusStorage(dataDir);
+ mPackageStatusStorage.initialize();
}
@After
@@ -56,6 +59,16 @@
}
@Test
+ public void initialize_fail() {
+ File readOnlyDir = new File("/system/does/not/exist");
+ PackageStatusStorage packageStatusStorage = new PackageStatusStorage(readOnlyDir);
+ try {
+ packageStatusStorage.initialize();
+ fail();
+ } catch (IOException expected) {}
+ }
+
+ @Test
public void getPackageStatus_initialState() {
assertNull(mPackageStatusStorage.getPackageStatus());
}
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..9cf6392 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
@@ -30,8 +30,13 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
+import java.io.File;
+import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneId;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -57,7 +62,7 @@
private ConfigHelper mMockConfigHelper;
private PackageManagerHelper mMockPackageManagerHelper;
- private FakeClockHelper mFakeClock;
+ private FakeClock mFakeClock;
private FakeIntentHelper mFakeIntentHelper;
private PackageStatusStorage mPackageStatusStorage;
private PackageTracker mPackageTracker;
@@ -66,7 +71,7 @@
public void setUp() throws Exception {
Context context = InstrumentationRegistry.getContext();
- mFakeClock = new FakeClockHelper();
+ mFakeClock = new FakeClock();
// Read-only interfaces so are easy to mock.
mMockConfigHelper = mock(ConfigHelper.class);
@@ -101,7 +106,7 @@
configureTrackingDisabled();
// Initialize the tracker.
- mPackageTracker.start();
+ assertFalse(mPackageTracker.start());
// Check the IntentHelper was not initialized.
mFakeIntentHelper.assertNotInitialized();
@@ -116,7 +121,7 @@
configureTrackingDisabled();
// Initialize the tracker.
- mPackageTracker.start();
+ assertFalse(mPackageTracker.start());
// Check reliability triggering state.
mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
@@ -138,7 +143,7 @@
configureTrackingDisabled();
// Initialize the tracker.
- mPackageTracker.start();
+ assertFalse(mPackageTracker.start());
// Check reliability triggering state.
mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
@@ -163,7 +168,7 @@
mPackageStatusStorage.generateCheckToken(INITIAL_APP_PACKAGE_VERSIONS);
// Initialize the tracker.
- mPackageTracker.start();
+ assertFalse(mPackageTracker.start());
// Check reliability triggering state.
mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
@@ -259,6 +264,35 @@
}
@Test
+ public void trackingEnabled_storageInitializationFails() throws Exception {
+ // Create a PackageStateStorage that will fail to initialize.
+ PackageStatusStorage packageStatusStorage =
+ new PackageStatusStorage(new File("/system/does/not/exist"));
+
+ // Create a new PackageTracker to use the bad storage.
+ mPackageTracker = new PackageTracker(
+ mFakeClock,
+ mMockConfigHelper,
+ mMockPackageManagerHelper,
+ packageStatusStorage,
+ mFakeIntentHelper);
+
+ // Set up device configuration.
+ configureTrackingEnabled();
+ configureReliabilityConfigSettingsOk();
+ configureValidApplications();
+
+ // Initialize the tracker.
+ assertFalse(mPackageTracker.start());
+
+ // Check the IntentHelper was not initialized.
+ mFakeIntentHelper.assertNotInitialized();
+
+ // Check reliability triggering state.
+ mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
+ }
+
+ @Test
public void trackingEnabled_packageUpdate_badUpdateAppManifestEntry() throws Exception {
// Set up device configuration.
configureTrackingEnabled();
@@ -266,7 +300,7 @@
configureValidApplications();
// Initialize the tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -303,7 +337,7 @@
configureValidApplications();
// Initialize the tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -348,7 +382,7 @@
configureValidApplications();
// Initialize the tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -396,7 +430,7 @@
configureValidApplications();
// Initialize the tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -435,7 +469,7 @@
configureValidApplications();
// Initialize the tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -481,7 +515,7 @@
configureValidApplications();
// Initialize the tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -530,7 +564,7 @@
configureValidApplications();
// Initialize the tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -590,7 +624,7 @@
configureValidApplications();
// Initialize the package tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -652,7 +686,7 @@
configureValidApplications();
// Initialize the package tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -708,7 +742,7 @@
configureValidApplications();
// Initialize the package tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -757,7 +791,7 @@
PackageVersions packageVersions = configureValidApplications();
// Initialize the package tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -794,7 +828,7 @@
PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
// Initialize the package tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -834,7 +868,7 @@
PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
// Initialize the package tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -880,7 +914,7 @@
PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
// Initialize the package tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -939,7 +973,7 @@
PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
// Initialize the package tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -1014,7 +1048,7 @@
PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
// Initialize the package tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -1080,7 +1114,7 @@
PackageStatus.CHECK_COMPLETED_SUCCESS, currentPackageVersions);
// Initialize the package tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -1135,7 +1169,7 @@
PackageStatus.CHECK_COMPLETED_SUCCESS, currentPackageVersions);
// Initialize the package tracker.
- mPackageTracker.start();
+ assertTrue(mPackageTracker.start());
// Check the intent helper is properly configured.
checkIntentHelperInitializedAndReliabilityTrackingEnabled();
@@ -1246,13 +1280,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);
}
@@ -1444,18 +1478,33 @@
}
}
- private static class FakeClockHelper implements ClockHelper {
+ private static class FakeClock extends Clock {
private long currentTime = 1000;
@Override
- public long currentTimestamp() {
+ public long millis() {
return currentTime;
}
public void incrementClock(long millis) {
currentTime += millis;
}
+
+ @Override
+ public ZoneId getZone() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Clock withZone(ZoneId zone) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Instant instant() {
+ throw new UnsupportedOperationException();
+ }
}
/**
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..86ce90c 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,13 @@
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.REASON_PREDICTED;
+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 +34,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 +284,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 +316,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);
@@ -361,4 +365,29 @@
reportEvent(controller, NOTIFICATION_SEEN, mInjector.mElapsedRealtime);
assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(controller));
}
+
+ @Test
+ public void testPredictionTimedout() throws Exception {
+ AppStandbyController controller = setupController();
+ setChargingState(controller, false);
+ controller.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
+ REASON_PREDICTED + "CTS", 1 * HOUR_MS);
+
+ // Fast forward 12 hours
+ mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD;
+ controller.checkIdleStates(USER_ID);
+ // Should still be in predicted bucket, since prediction timeout is 1 day since prediction
+ assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(controller));
+ // Fast forward two more hours
+ mInjector.mElapsedRealtime += 2 * HOUR_MS;
+ controller.checkIdleStates(USER_ID);
+ // Should have now applied prediction timeout
+ assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(controller));
+
+ // Fast forward RARE bucket
+ mInjector.mElapsedRealtime += RARE_THRESHOLD;
+ controller.checkIdleStates(USER_ID);
+ // Should continue to apply prediction timeout
+ assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(controller));
+ }
}
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..9ad41cd 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -39,9 +39,9 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mockito;
import org.mockito.Matchers;
-import org.mockito.compat.ArgumentMatcher;
import java.lang.Integer;
import java.util.concurrent.CountDownLatch;
@@ -141,7 +141,7 @@
}
// For matching the package name of a PackageInfo
- private class IsPackageInfoWithName extends ArgumentMatcher<PackageInfo> {
+ private class IsPackageInfoWithName implements ArgumentMatcher<PackageInfo> {
private final String mPackageName;
IsPackageInfoWithName(String name) {
@@ -149,8 +149,8 @@
}
@Override
- public boolean matchesObject(Object p) {
- return ((PackageInfo) p).packageName.equals(mPackageName);
+ public boolean matches(PackageInfo p) {
+ return p.packageName.equals(mPackageName);
}
@Override
@@ -202,10 +202,10 @@
private static PackageInfo createPackageInfo(String packageName, boolean enabled, boolean valid,
boolean installed, Signature[] signatures, long updateTime, boolean hidden,
- int versionCode, boolean isSystemApp) {
+ long versionCode, boolean isSystemApp) {
PackageInfo p = createPackageInfo(packageName, enabled, valid, installed, signatures,
updateTime, hidden);
- p.versionCode = versionCode;
+ p.setLongVersionCode(versionCode);
p.applicationInfo.versionCode = versionCode;
if (isSystemApp) p.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
return p;
@@ -1495,7 +1495,7 @@
public void testGetCurrentWebViewPackage() {
PackageInfo firstPackage = createPackageInfo("first", true /* enabled */,
true /* valid */, true /* installed */);
- firstPackage.versionCode = 100;
+ firstPackage.setLongVersionCode(100);
firstPackage.versionName = "first package version";
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
new WebViewProviderInfo(firstPackage.packageName, "", true, false, null)};
@@ -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..70906df 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
@@ -48,13 +48,17 @@
final SurfaceControl mControl = mock(SurfaceControl.class);
final SurfaceControl.Transaction mTransaction = mock(SurfaceControl.Transaction.class);
+ TestWindowContainer() {
+ super(sWm);
+ }
+
@Override
- SurfaceControl getSurfaceControl() {
+ public SurfaceControl getSurfaceControl() {
return mControl;
}
@Override
- SurfaceControl.Transaction getPendingTransaction() {
+ public SurfaceControl.Transaction getPendingTransaction() {
return mTransaction;
}
}
@@ -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,18 +86,19 @@
}
}
+
@Override
SurfaceControl.Builder makeChildSurface(WindowContainer child) {
return new MockSurfaceBuilder(mSession);
}
@Override
- SurfaceControl getSurfaceControl() {
+ public SurfaceControl getSurfaceControl() {
return mHostControl;
}
@Override
- SurfaceControl.Transaction getPendingTransaction() {
+ public SurfaceControl.Transaction getPendingTransaction() {
return mHostTransaction;
}
}
@@ -101,8 +110,8 @@
@Before
public void setUp() throws Exception {
super.setUp();
-
mHost = new MockSurfaceBuildingContainer();
+
mTransaction = mock(SurfaceControl.Transaction.class);
mDimmer = new Dimmer(mHost);
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
new file mode 100644
index 0000000..ce76a22
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
@@ -0,0 +1,88 @@
+/*
+ * 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.wm;
+
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.InputChannel;
+import android.view.Surface;
+import android.view.SurfaceSession;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+/**
+ * Tests for the {@link DragDropController} class.
+ *
+ * atest com.android.server.wm.DragDropControllerTests
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@Presubmit
+public class DragDropControllerTests extends WindowTestsBase {
+ private static final int TIMEOUT_MS = 1000;
+ private DragDropController mTarget;
+ private WindowState mWindow;
+ private IBinder mToken;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ assertNotNull(sWm.mDragDropController);
+ mTarget = sWm.mDragDropController;
+ mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
+ synchronized (sWm.mWindowMap) {
+ // Because sWm is a static object, the previous operation may remain.
+ assertFalse(mTarget.dragDropActiveLocked());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ if (mToken != null) {
+ mTarget.cancelDragAndDrop(mToken);
+ }
+ }
+
+ @Test
+ public void testPrepareDrag() throws Exception {
+ final Surface surface = new Surface();
+ mToken = mTarget.prepareDrag(
+ new SurfaceSession(), 0, 0, mWindow.mClient, 0, 100, 100, surface);
+ assertNotNull(mToken);
+ }
+
+ @Test
+ public void testPrepareDrag_ZeroSizeSurface() throws Exception {
+ final Surface surface = new Surface();
+ mToken = mTarget.prepareDrag(
+ new SurfaceSession(), 0, 0, mWindow.mClient, 0, 0, 0, surface);
+ assertNull(mToken);
+ }
+}
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/SurfaceAnimationRunnerTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
new file mode 100644
index 0000000..c309611
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -0,0 +1,214 @@
+/*
+ * 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.wm;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.animation.AnimationHandler;
+import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
+import android.animation.ValueAnimator;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.Choreographer;
+import android.view.Choreographer.FrameCallback;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+import android.view.animation.Animation;
+import android.view.animation.TranslateAnimation;
+
+import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
+import com.android.server.wm.SurfaceAnimationRunner.AnimatorFactory;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Test class for {@link SurfaceAnimationRunner}.
+ *
+ * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimationRunnerTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class SurfaceAnimationRunnerTest extends WindowTestsBase {
+
+ @Mock SurfaceControl mMockSurface;
+ @Mock Transaction mMockTransaction;
+ @Mock AnimationSpec mMockAnimationSpec;
+ @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ private SurfaceAnimationRunner mSurfaceAnimationRunner;
+ private CountDownLatch mFinishCallbackLatch;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ mFinishCallbackLatch = new CountDownLatch(1);
+ mSurfaceAnimationRunner = new SurfaceAnimationRunner(null /* callbackProvider */, null,
+ mMockTransaction);
+ }
+
+ private void finishedCallback() {
+ mFinishCallbackLatch.countDown();
+ }
+
+ @Test
+ public void testAnimation() throws Exception {
+ mSurfaceAnimationRunner
+ .startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
+ this::finishedCallback);
+
+ // Ensure that the initial transformation has been applied.
+ final Matrix m = new Matrix();
+ m.setTranslate(-10, 0);
+ verify(mMockTransaction, atLeastOnce()).setMatrix(eq(mMockSurface), eq(m), any());
+ verify(mMockTransaction, atLeastOnce()).setAlpha(eq(mMockSurface), eq(1.0f));
+
+ mFinishCallbackLatch.await(1, SECONDS);
+ assertFinishCallbackCalled();
+
+ m.setTranslate(10, 0);
+ verify(mMockTransaction, atLeastOnce()).setMatrix(eq(mMockSurface), eq(m), any());
+
+ // At least 3 times: After initialization, first frame, last frame.
+ verify(mMockTransaction, atLeast(3)).setAlpha(eq(mMockSurface), eq(1.0f));
+ }
+
+ @Test
+ public void testCancel_notStarted() throws Exception {
+ mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), null,
+ mMockTransaction);
+ mSurfaceAnimationRunner
+ .startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
+ this::finishedCallback);
+ mSurfaceAnimationRunner.onAnimationCancelled(mMockSurface);
+ waitUntilHandlersIdle();
+ assertTrue(mSurfaceAnimationRunner.mPendingAnimations.isEmpty());
+ assertFinishCallbackNotCalled();
+ }
+
+ @Test
+ public void testCancel_running() throws Exception {
+ mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), null,
+ mMockTransaction);
+ mSurfaceAnimationRunner.startAnimation(createTranslateAnimation(), mMockSurface,
+ mMockTransaction, this::finishedCallback);
+ waitUntilNextFrame();
+ assertFalse(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
+ mSurfaceAnimationRunner.onAnimationCancelled(mMockSurface);
+ assertTrue(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
+ waitUntilHandlersIdle();
+ assertFinishCallbackNotCalled();
+ }
+
+ @Test
+ public void testCancel_sneakyCancelBeforeUpdate() throws Exception {
+ mSurfaceAnimationRunner = new SurfaceAnimationRunner(null, () -> new ValueAnimator() {
+ {
+ setFloatValues(0f, 1f);
+ }
+
+ @Override
+ public void addUpdateListener(AnimatorUpdateListener listener) {
+ super.addUpdateListener(animation -> {
+ // Sneaky test cancels animation just before applying frame to simulate
+ // interleaving of multiple threads. Muahahaha
+ if (animation.getCurrentPlayTime() > 0) {
+ mSurfaceAnimationRunner.onAnimationCancelled(mMockSurface);
+ }
+ listener.onAnimationUpdate(animation);
+ });
+ }
+ }, mMockTransaction);
+ when(mMockAnimationSpec.getDuration()).thenReturn(200L);
+ mSurfaceAnimationRunner.startAnimation(mMockAnimationSpec, mMockSurface, mMockTransaction,
+ this::finishedCallback);
+ waitUntilNextFrame();
+ assertFalse(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
+ verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L));
+ }
+
+ private void waitUntilNextFrame() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ mSurfaceAnimationRunner.mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT,
+ latch::countDown, null /* token */);
+ latch.await();
+ }
+
+ private void assertFinishCallbackCalled() {
+ assertEquals(0, mFinishCallbackLatch.getCount());
+ }
+
+ private void assertFinishCallbackNotCalled() {
+ assertEquals(1, mFinishCallbackLatch.getCount());
+ }
+
+ private AnimationSpec createTranslateAnimation() {
+ final Animation a = new TranslateAnimation(-10, 10, 0, 0);
+ a.initialize(0, 0, 0, 0);
+ a.setDuration(50);
+ return new WindowAnimationSpec(a, new Point(0, 0));
+ }
+
+ /**
+ * Callback provider that doesn't animate at all.
+ */
+ private static final class NoOpFrameCallbackProvider implements AnimationFrameCallbackProvider {
+
+ @Override
+ public void postFrameCallback(FrameCallback callback) {
+ }
+
+ @Override
+ public void postCommitCallback(Runnable runnable) {
+ }
+
+ @Override
+ public long getFrameTime() {
+ return 0;
+ }
+
+ @Override
+ public long getFrameDelay() {
+ return 0;
+ }
+
+ @Override
+ public void setFrameDelay(long delay) {
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
new file mode 100644
index 0000000..6f739ca
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -0,0 +1,230 @@
+/*
+ * 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.wm;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+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.SurfaceControl.Builder;
+import android.view.SurfaceControl.Transaction;
+import android.view.SurfaceSession;
+
+import com.android.server.wm.SurfaceAnimator.Animatable;
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+
+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;
+
+/**
+ * Test class for {@link SurfaceAnimatorTest}.
+ *
+ * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimatorTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class SurfaceAnimatorTest extends WindowTestsBase {
+
+ @Mock AnimationAdapter mSpec;
+ @Mock AnimationAdapter mSpec2;
+ @Mock Transaction mTransaction;
+
+ private SurfaceSession mSession = new SurfaceSession();
+ private MyAnimatable mAnimatable;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ MockitoAnnotations.initMocks(this);
+ mAnimatable = new MyAnimatable();
+ }
+
+ @Test
+ public void testRunAnimation() throws Exception {
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
+ OnAnimationFinishedCallback.class);
+
+ assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+ assertNotNull(mAnimatable.mSurfaceAnimator.getAnimation());
+ verify(mTransaction).reparent(eq(mAnimatable.mSurface), eq(mAnimatable.mLeash.getHandle()));
+ verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
+
+ callbackCaptor.getValue().onAnimationFinished(mSpec);
+ assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
+ assertNull(mAnimatable.mSurfaceAnimator.getAnimation());
+ assertTrue(mAnimatable.mFinishedCallbackCalled);
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ // TODO: Verify reparenting once we use mPendingTransaction to reparent it back
+ }
+
+ @Test
+ public void testOverrideAnimation() throws Exception {
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ final SurfaceControl firstLeash = mAnimatable.mLeash;
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
+
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(firstLeash));
+ assertFalse(mAnimatable.mFinishedCallbackCalled);
+
+ final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
+ OnAnimationFinishedCallback.class);
+ assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+ assertNotNull(mAnimatable.mSurfaceAnimator.getAnimation());
+ verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
+
+ // First animation was finished, but this shouldn't cancel the second animation
+ callbackCaptor.getValue().onAnimationFinished(mSpec);
+ assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+
+ // Second animation was finished
+ verify(mSpec2).startAnimation(any(), any(), callbackCaptor.capture());
+ callbackCaptor.getValue().onAnimationFinished(mSpec2);
+ assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
+ assertTrue(mAnimatable.mFinishedCallbackCalled);
+ }
+
+ @Test
+ public void testCancelAnimation() throws Exception {
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+ mAnimatable.mSurfaceAnimator.cancelAnimation();
+ assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
+ verify(mSpec).onAnimationCancelled(any());
+ assertTrue(mAnimatable.mFinishedCallbackCalled);
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ }
+
+ @Test
+ public void testDelayingAnimationStart() throws Exception {
+ mAnimatable.mSurfaceAnimator.startDelayingAnimationStart();
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ verifyZeroInteractions(mSpec);
+ assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+ mAnimatable.mSurfaceAnimator.endDelayingAnimationStart();
+ verify(mSpec).startAnimation(any(), any(), any());
+ }
+
+ @Test
+ public void testDelayingAnimationStartAndCancelled() throws Exception {
+ mAnimatable.mSurfaceAnimator.startDelayingAnimationStart();
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mAnimatable.mSurfaceAnimator.cancelAnimation();
+ verifyZeroInteractions(mSpec);
+ assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
+ assertTrue(mAnimatable.mFinishedCallbackCalled);
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ }
+
+ private class MyAnimatable implements Animatable {
+
+ final SurfaceControl mParent;
+ final SurfaceControl mSurface;
+ final ArrayList<SurfaceControl> mPendingDestroySurfaces = new ArrayList<>();
+ final SurfaceAnimator mSurfaceAnimator;
+ SurfaceControl mLeash;
+ boolean mFinishedCallbackCalled;
+
+ MyAnimatable() {
+ mParent = sWm.makeSurfaceBuilder(mSession)
+ .setName("test surface parent")
+ .setSize(3000, 3000)
+ .build();
+ mSurface = sWm.makeSurfaceBuilder(mSession)
+ .setName("test surface")
+ .setSize(1, 1)
+ .build();
+ mFinishedCallbackCalled = false;
+ mLeash = null;
+ mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, sWm);
+ }
+
+ @Override
+ public Transaction getPendingTransaction() {
+ return mTransaction;
+ }
+
+ @Override
+ public void commitPendingTransaction() {
+ }
+
+ @Override
+ public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
+ }
+
+ @Override
+ public void onAnimationLeashDestroyed(Transaction t) {
+ }
+
+ @Override
+ public void destroyAfterPendingTransaction(SurfaceControl surface) {
+ mPendingDestroySurfaces.add(surface);
+ }
+
+ @Override
+ public Builder makeAnimationLeash() {
+ return new SurfaceControl.Builder(mSession) {
+
+ @Override
+ public SurfaceControl build() {
+ mLeash = super.build();
+ return mLeash;
+ }
+ }.setParent(mParent);
+ }
+
+ @Override
+ public SurfaceControl getSurfaceControl() {
+ return mSurface;
+ }
+
+ @Override
+ public SurfaceControl getParentSurfaceControl() {
+ return mParent;
+ }
+
+ @Override
+ public int getSurfaceWidth() {
+ return 1;
+ }
+
+ @Override
+ public int getSurfaceHeight() {
+ return 1;
+ }
+
+ private final Runnable mFinishedCallback = () -> {
+ mFinishedCallbackCalled = true;
+ };
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java
new file mode 100644
index 0000000..89447a9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.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 com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.InputChannel;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+/**
+ * Tests for the {@link TaskPositioningController} class.
+ *
+ * atest com.android.server.wm.TaskPositioningControllerTests
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@Presubmit
+public class TaskPositioningControllerTests extends WindowTestsBase {
+ private static final int TIMEOUT_MS = 1000;
+ private TaskPositioningController mTarget;
+ private WindowState mWindow;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ assertNotNull(sWm.mTaskPositioningController);
+ mTarget = sWm.mTaskPositioningController;
+
+ when(sWm.mInputManager.transferTouchFocus(
+ any(InputChannel.class),
+ any(InputChannel.class))).thenReturn(true);
+
+ mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
+ mWindow.mInputChannel = new InputChannel();
+ synchronized (sWm.mWindowMap) {
+ sWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
+ }
+ }
+
+ @Test
+ public void testStartAndFinishPositioning() throws Exception {
+ synchronized (sWm.mWindowMap) {
+ assertFalse(mTarget.isPositioningLocked());
+ assertNull(mTarget.getDragWindowHandleLocked());
+ }
+
+ assertTrue(mTarget.startMovingTask(mWindow.mClient, 0, 0));
+
+ synchronized (sWm.mWindowMap) {
+ assertTrue(mTarget.isPositioningLocked());
+ assertNotNull(mTarget.getDragWindowHandleLocked());
+ }
+
+ assertTrue(sWm.mH.runWithScissors(() -> {
+ mTarget.finishPositioning();
+ }, TIMEOUT_MS));
+
+ assertFalse(mTarget.isPositioningLocked());
+ assertNull(mTarget.getDragWindowHandleLocked());
+ }
+
+ @Test
+ public void testHandleTapOutsideTask() throws Exception {
+ synchronized (sWm.mWindowMap) {
+
+ assertFalse(mTarget.isPositioningLocked());
+ assertNull(mTarget.getDragWindowHandleLocked());
+ }
+
+ final DisplayContent content = mock(DisplayContent.class);
+ when(content.findTaskForResizePoint(anyInt(), anyInt())).thenReturn(mWindow.getTask());
+ assertNotNull(mWindow.getTask().getTopVisibleAppMainWindow());
+
+ mTarget.handleTapOutsideTask(content, 0, 0);
+
+ synchronized (sWm.mWindowMap) {
+ assertTrue(mTarget.isPositioningLocked());
+ assertNotNull(mTarget.getDragWindowHandleLocked());
+ }
+
+ assertTrue(sWm.mH.runWithScissors(() -> {
+ mTarget.finishPositioning();
+ }, TIMEOUT_MS));
+
+ assertFalse(mTarget.isPositioningLocked());
+ assertNull(mTarget.getDragWindowHandleLocked());
+ }
+}
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/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..307deb4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -29,8 +29,6 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -193,7 +191,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 +206,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());
@@ -333,12 +331,19 @@
final TestWindowContainer child12 = child1.addChildWindow(builder.setIsAnimating(true));
final TestWindowContainer child21 = child2.addChildWindow();
- assertTrue(root.isAnimating());
+ assertFalse(root.isAnimating());
assertTrue(child1.isAnimating());
- assertFalse(child11.isAnimating());
+ assertTrue(child11.isAnimating());
assertTrue(child12.isAnimating());
assertFalse(child2.isAnimating());
assertFalse(child21.isAnimating());
+
+ assertTrue(root.isSelfOrChildAnimating());
+ assertTrue(child1.isSelfOrChildAnimating());
+ assertFalse(child11.isSelfOrChildAnimating());
+ assertTrue(child12.isSelfOrChildAnimating());
+ assertFalse(child2.isSelfOrChildAnimating());
+ assertFalse(child21.isSelfOrChildAnimating());
}
@Test
@@ -587,6 +592,7 @@
TestWindowContainer(int layer, boolean isAnimating, boolean isVisible,
Integer orientation) {
+ super(sWm);
mLayer = layer;
mIsAnimating = isAnimating;
mIsVisible = isVisible;
@@ -629,8 +635,8 @@
}
@Override
- boolean isAnimating() {
- return mIsAnimating || super.isAnimating();
+ boolean isSelfAnimating() {
+ return mIsAnimating;
}
@Override
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 fdcf57b..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,12 +22,12 @@
import android.app.ActivityManager.TaskDescription;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.graphics.Rect;
-import android.os.Debug;
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;
@@ -38,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.
*
@@ -158,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);
@@ -173,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.
@@ -194,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.
@@ -202,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);
@@ -222,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
@@ -237,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
@@ -247,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);
}
@@ -277,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);
@@ -289,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;
@@ -306,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;
@@ -338,13 +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);
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);
@@ -357,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
@@ -394,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);
@@ -413,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;
@@ -426,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/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index b2334e8..5f58744 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -189,7 +189,6 @@
public static class TestTask extends Task {
boolean mShouldDeferRemoval = false;
boolean mOnDisplayChangedCalled = false;
- private boolean mUseLocalIsAnimating = false;
private boolean mIsAnimating = false;
TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service,
@@ -214,12 +213,11 @@
}
@Override
- boolean isAnimating() {
- return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating();
+ boolean isSelfAnimating() {
+ return mIsAnimating;
}
void setLocalIsAnimating(boolean isAnimating) {
- mUseLocalIsAnimating = true;
mIsAnimating = isAnimating;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 4c5e291..c699a94 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -185,6 +185,7 @@
void waitUntilHandlersIdle() {
sWm.mH.runWithScissors(() -> { }, 0);
sWm.mAnimationHandler.runWithScissors(() -> { }, 0);
+ SurfaceAnimationThread.getHandler().runWithScissors(() -> { }, 0);
}
private WindowToken createWindowToken(
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 04f5e5e..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,35 +16,32 @@
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_SYSTEM_OVERLAY;
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.
@@ -78,7 +75,7 @@
}
int getLayer(SurfaceControl sc) {
- return mLayersForControl.get(sc);
+ return mLayersForControl.getOrDefault(sc, 0);
}
SurfaceControl getRelativeLayer(SurfaceControl sc) {
@@ -124,6 +121,7 @@
// would miss construction of the top-level layers.
mTransaction = new LayerRecordingTransaction();
sWm.mSurfaceBuilderFactory = new HierarchyRecordingBuilderFactory();
+ sWm.mTransactionFactory = () -> mTransaction;
}
@After
@@ -343,4 +341,22 @@
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..019bcbd3 100644
--- a/services/tests/shortcutmanagerutils/Android.mk
+++ b/services/tests/shortcutmanagerutils/Android.mk
@@ -21,7 +21,7 @@
LOCAL_JAVA_LIBRARIES := \
mockito-target \
- 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 83%
rename from services/tests/notification/Android.mk
rename to services/tests/uiservicestests/Android.mk
index 597a584..d8e14ec 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)
@@ -10,7 +10,8 @@
# Include test java files and source from notifications package.
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
- $(call all-java-files-under, ../../core/java/com/android/server/notification)
+ $(call all-java-files-under, ../../core/java/com/android/server/notification) \
+ $(call all-java-files-under, ../../core/java/com/android/server/slice) \
LOCAL_STATIC_JAVA_LIBRARIES := \
frameworks-base-testutils \
@@ -25,12 +26,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 86%
rename from services/tests/notification/AndroidManifest.xml
rename to services/tests/uiservicestests/AndroidManifest.xml
index c20020a..f022dcf 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" />
@@ -28,10 +28,13 @@
<application>
<uses-library android:name="android.test.runner" />
+
+ <provider android:name=".DummyProvider"
+ android:authorities="com.android.services.uitests" />
</application>
<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/uiservicestests/src/com/android/frameworks/tests/uiservices/DummyProvider.java b/services/tests/uiservicestests/src/com/android/frameworks/tests/uiservices/DummyProvider.java
new file mode 100644
index 0000000..574c226
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/frameworks/tests/uiservices/DummyProvider.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.frameworks.tests.uiservices;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class DummyProvider extends ContentProvider {
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
new file mode 100644
index 0000000..f534b5c
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
@@ -0,0 +1,38 @@
+/*
+ * 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 android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.testing.TestableContext;
+
+import org.junit.Before;
+import org.junit.Rule;
+
+
+public class UiServiceTestCase {
+ @Rule
+ public final TestableContext mContext =
+ new TestableContext(InstrumentationRegistry.getContext(), null);
+
+ protected TestableContext getContext() {
+ return mContext;
+ }
+
+ @Before
+ public void setup() {
+ // Share classloader to allow package access.
+ System.setProperty("dexmaker.share_classloader", "true");
+ }
+}
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 95%
rename from services/tests/notification/src/com/android/server/notification/AlertRateLimiterTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/AlertRateLimiterTest.java
index faf6a9b..d4c41e0 100644
--- a/services/tests/notification/src/com/android/server/notification/AlertRateLimiterTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/AlertRateLimiterTest.java
@@ -22,13 +22,16 @@
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.UiServiceTestCase;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class AlertRateLimiterTest extends NotificationTestCase {
+public class AlertRateLimiterTest extends UiServiceTestCase {
private long mTestStartTime;
private
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 96%
rename from services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
index 262516d..142041a 100644
--- a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
@@ -27,13 +27,13 @@
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationChannel;
-import android.app.NotificationManager;
import android.os.UserHandle;
-import android.provider.Settings.Secure;
import android.service.notification.StatusBarNotification;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.server.UiServiceTestCase;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -42,7 +42,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class BadgeExtractorTest extends NotificationTestCase {
+public class BadgeExtractorTest extends UiServiceTestCase {
@Mock RankingConfig mConfig;
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 99%
rename from services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 0b4d61f..a92f7e7 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -58,13 +58,13 @@
import android.service.notification.StatusBarNotification;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Slog;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
import android.view.accessibility.IAccessibilityManagerClient;
import com.android.internal.util.IntPair;
+import com.android.server.UiServiceTestCase;
import com.android.server.lights.Light;
import org.junit.Before;
@@ -74,12 +74,10 @@
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class BuzzBeepBlinkTest extends NotificationTestCase {
+public class BuzzBeepBlinkTest extends UiServiceTestCase {
@Mock AudioManager mAudioManager;
@Mock Vibrator mVibrator;
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 97%
rename from services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
index f92bd84..97f2104 100644
--- a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
@@ -28,6 +28,8 @@
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.server.UiServiceTestCase;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -37,7 +39,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class GlobalSortKeyComparatorTest extends NotificationTestCase {
+public class GlobalSortKeyComparatorTest extends UiServiceTestCase {
private final String PKG = "PKG";
private final int UID = 1111111;
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 98%
rename from services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
index f75c648..8d4c5b1 100644
--- a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
@@ -38,6 +38,8 @@
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.server.UiServiceTestCase;
+
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
@@ -45,7 +47,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class GroupHelperTest extends NotificationTestCase {
+public class GroupHelperTest extends UiServiceTestCase {
private @Mock GroupHelper.Callback mCallback;
private GroupHelper mGroupHelper;
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 96%
rename from services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java
index d325e10..73d5961 100644
--- a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java
@@ -30,7 +30,6 @@
import android.test.suitebuilder.annotation.SmallTest;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import static org.mockito.Matchers.anyInt;
@@ -39,9 +38,11 @@
import static org.junit.Assert.assertEquals;
+import com.android.server.UiServiceTestCase;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class ImportanceExtractorTest extends NotificationTestCase {
+public class ImportanceExtractorTest extends UiServiceTestCase {
@Mock RankingConfig mConfig;
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 99%
rename from services/tests/notification/src/com/android/server/notification/ManagedServicesTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index a4b9b25..9ef0ec7 100644
--- a/services/tests/notification/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -49,6 +49,7 @@
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
+import com.android.server.UiServiceTestCase;
import com.google.android.collect.Lists;
@@ -68,7 +69,7 @@
import java.util.ArrayList;
import java.util.List;
-public class ManagedServicesTest extends NotificationTestCase {
+public class ManagedServicesTest extends UiServiceTestCase {
@Mock
private IPackageManager mIpm;
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 97%
rename from services/tests/notification/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
index e527644..fd674f0 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
@@ -31,12 +31,14 @@
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
+import com.android.server.UiServiceTestCase;
+
import org.junit.Test;
import java.util.ArrayList;
import java.util.Objects;
-public class NotificationAdjustmentExtractorTest extends NotificationTestCase {
+public class NotificationAdjustmentExtractorTest extends UiServiceTestCase {
@Test
public void testExtractsAdjustment() {
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 92%
rename from services/tests/notification/src/com/android/server/notification/NotificationChannelExtractorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
index d75213c..eb45960 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationChannelExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
@@ -16,7 +16,6 @@
package com.android.server.notification;
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
@@ -31,17 +30,17 @@
import android.app.Notification;
import android.app.NotificationChannel;
-import android.app.PendingIntent;
-import android.content.Intent;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
+import com.android.server.UiServiceTestCase;
+
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-public class NotificationChannelExtractorTest extends NotificationTestCase {
+public class NotificationChannelExtractorTest extends UiServiceTestCase {
@Mock RankingConfig mConfig;
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 95%
rename from services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelTest.java
index f457f6a..2241047 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelTest.java
@@ -26,6 +26,7 @@
import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.util.FastXmlSerializer;
+import com.android.server.UiServiceTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,7 +37,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class NotificationChannelTest extends NotificationTestCase {
+public class NotificationChannelTest extends UiServiceTestCase {
@Test
public void testWriteToParcel() {
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 98%
rename from services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
index 1e5f96f..3dcd5b9 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
@@ -38,6 +38,8 @@
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.server.UiServiceTestCase;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,7 +52,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class NotificationComparatorTest extends NotificationTestCase {
+public class NotificationComparatorTest extends UiServiceTestCase {
@Mock Context mContext;
@Mock TelecomManager mTm;
@Mock RankingHandler handler;
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 96%
rename from services/tests/notification/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java
index 85852f9..00d93de 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java
@@ -32,9 +32,11 @@
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
+import com.android.server.UiServiceTestCase;
+
import org.junit.Test;
-public class NotificationIntrusivenessExtractorTest extends NotificationTestCase {
+public class NotificationIntrusivenessExtractorTest extends UiServiceTestCase {
@Test
public void testNonIntrusive() {
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 98%
rename from services/tests/notification/src/com/android/server/notification/NotificationListenerServiceTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
index d767ba2..f4313b8 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationListenerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
@@ -37,6 +37,8 @@
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.server.UiServiceTestCase;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,7 +47,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class NotificationListenerServiceTest extends NotificationTestCase {
+public class NotificationListenerServiceTest extends UiServiceTestCase {
private String[] mKeys = new String[] { "key", "key1", "key2", "key3"};
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 89%
rename from services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 55ec133..ad3fecf 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -83,6 +83,7 @@
import android.util.AtomicFile;
import com.android.internal.statusbar.NotificationVisibility;
+import com.android.server.UiServiceTestCase;
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
import com.android.server.notification.NotificationManagerService.NotificationAssistants;
@@ -92,7 +93,9 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.*;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
import java.io.BufferedInputStream;
@@ -108,7 +111,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
-public class NotificationManagerServiceTest extends NotificationTestCase {
+public class NotificationManagerServiceTest extends UiServiceTestCase {
private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
private final int mUid = Binder.getCallingUid();
private NotificationManagerService mService;
@@ -873,6 +876,77 @@
}
@Test
+ public void testCancelAllCancelNotificationsFromListener_ForegroundServiceFlag()
+ throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ child2.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ final NotificationRecord newGroup = generateNotificationRecord(
+ mTestNotificationChannel, 4, "group2", false);
+ mService.addNotification(parent);
+ mService.addNotification(child);
+ mService.addNotification(child2);
+ mService.addNotification(newGroup);
+ mService.getBinderService().cancelNotificationsFromListener(null, null);
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(parent.sbn.getPackageName());
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
+ public void testCancelAllCancelNotificationsFromListener_ForegroundServiceFlagWithParameter()
+ throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ child2.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ final NotificationRecord newGroup = generateNotificationRecord(
+ mTestNotificationChannel, 4, "group2", false);
+ mService.addNotification(parent);
+ mService.addNotification(child);
+ mService.addNotification(child2);
+ mService.addNotification(newGroup);
+ String[] keys = {parent.sbn.getKey(), child.sbn.getKey(),
+ child2.sbn.getKey(), newGroup.sbn.getKey()};
+ mService.getBinderService().cancelNotificationsFromListener(null, keys);
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(parent.sbn.getPackageName());
+ assertEquals(1, notifs.length);
+ }
+
+ @Test
+ public void testUserInitiatedCancelAllWithGroup_ForegroundServiceFlag() throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ child2.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ final NotificationRecord newGroup = generateNotificationRecord(
+ mTestNotificationChannel, 4, "group2", false);
+ mService.addNotification(parent);
+ mService.addNotification(child);
+ mService.addNotification(child2);
+ mService.addNotification(newGroup);
+ mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
+ parent.getUserId());
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(parent.sbn.getPackageName());
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
public void testFindGroupNotificationsLocked() throws Exception {
// make sure the same notification can be found in both lists and returned
final NotificationRecord group1 = generateNotificationRecord(
@@ -912,6 +986,157 @@
}
@Test
+ public void testCancelAllNotifications_CancelsNoClearFlagOnGoing() throws Exception {
+ final NotificationRecord notif = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ notif.getNotification().flags |= Notification.FLAG_NO_CLEAR;
+ mService.addNotification(notif);
+ mService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0,
+ Notification.FLAG_ONGOING_EVENT, true, notif.getUserId(), 0, null);
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(notif.sbn.getPackageName());
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
+ public void testCancelAllCancelNotificationsFromListener_NoClearFlagWithParameter()
+ throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ child2.getNotification().flags |= Notification.FLAG_NO_CLEAR;
+ final NotificationRecord newGroup = generateNotificationRecord(
+ mTestNotificationChannel, 4, "group2", false);
+ mService.addNotification(parent);
+ mService.addNotification(child);
+ mService.addNotification(child2);
+ mService.addNotification(newGroup);
+ String[] keys = {parent.sbn.getKey(), child.sbn.getKey(),
+ child2.sbn.getKey(), newGroup.sbn.getKey()};
+ mService.getBinderService().cancelNotificationsFromListener(null, keys);
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(parent.sbn.getPackageName());
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
+ public void testAppInitiatedCancelAllNotifications_CancelsOnGoingFlag() throws Exception {
+ final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
+ sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ sbn.getId(), sbn.getNotification(), sbn.getUserId());
+ mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(sbn.getPackageName());
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
+ public void testCancelAllNotifications_CancelsOnGoingFlag() throws Exception {
+ final NotificationRecord notif = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ notif.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ mService.addNotification(notif);
+ mService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0, 0, true,
+ notif.getUserId(), 0, null);
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(notif.sbn.getPackageName());
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
+ public void testUserInitiatedCancelAllOnClearAll_OnGoingFlag() throws Exception {
+ final NotificationRecord notif = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ notif.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ mService.addNotification(notif);
+
+ mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
+ notif.getUserId());
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(notif.sbn.getPackageName());
+ assertEquals(1, notifs.length);
+ }
+
+ @Test
+ public void testCancelAllCancelNotificationsFromListener_OnGoingFlag() throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ child2.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ final NotificationRecord newGroup = generateNotificationRecord(
+ mTestNotificationChannel, 4, "group2", false);
+ mService.addNotification(parent);
+ mService.addNotification(child);
+ mService.addNotification(child2);
+ mService.addNotification(newGroup);
+ mService.getBinderService().cancelNotificationsFromListener(null, null);
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(parent.sbn.getPackageName());
+ assertEquals(1, notifs.length);
+ }
+
+ @Test
+ public void testCancelAllCancelNotificationsFromListener_OnGoingFlagWithParameter()
+ throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ child2.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ final NotificationRecord newGroup = generateNotificationRecord(
+ mTestNotificationChannel, 4, "group2", false);
+ mService.addNotification(parent);
+ mService.addNotification(child);
+ mService.addNotification(child2);
+ mService.addNotification(newGroup);
+ String[] keys = {parent.sbn.getKey(), child.sbn.getKey(),
+ child2.sbn.getKey(), newGroup.sbn.getKey()};
+ mService.getBinderService().cancelNotificationsFromListener(null, keys);
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(parent.sbn.getPackageName());
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
+ public void testUserInitiatedCancelAllWithGroup_OnGoingFlag() throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ child2.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ final NotificationRecord newGroup = generateNotificationRecord(
+ mTestNotificationChannel, 4, "group2", false);
+ mService.addNotification(parent);
+ mService.addNotification(child);
+ mService.addNotification(child2);
+ mService.addNotification(newGroup);
+ mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
+ parent.getUserId());
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(parent.sbn.getPackageName());
+ assertEquals(1, notifs.length);
+ }
+
+ @Test
public void testTvExtenderChannelOverride_onTv() throws Exception {
mService.setIsTelevision(true);
mService.setRankingHelper(mRankingHelper);
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 99%
rename from services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index ef26705a..a5fa903 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -53,6 +53,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.server.UiServiceTestCase;
import org.junit.Before;
import org.junit.Test;
@@ -65,7 +66,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class NotificationRecordTest extends NotificationTestCase {
+public class NotificationRecordTest extends UiServiceTestCase {
private final Context mMockContext = Mockito.mock(Context.class);
@Mock PackageManager mPm;
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 96%
rename from services/tests/notification/src/com/android/server/notification/NotificationStatsTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java
index fec2811..4f153ee 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationStatsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java
@@ -11,12 +11,14 @@
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.server.UiServiceTestCase;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class NotificationStatsTest extends NotificationTestCase {
+public class NotificationStatsTest extends UiServiceTestCase {
@Test
public void testConstructor() {
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 97%
rename from services/tests/notification/src/com/android/server/notification/NotificationTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
index 4165e9e..4bfb236 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
@@ -33,6 +33,8 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import com.android.server.UiServiceTestCase;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -41,7 +43,7 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
-public class NotificationTest extends NotificationTestCase {
+public class NotificationTest extends UiServiceTestCase {
@Mock
ActivityManager mAm;
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 99%
rename from services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
index 2d03f11..abfc54d 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -65,6 +65,7 @@
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
+import com.android.server.UiServiceTestCase;
import org.json.JSONArray;
import org.json.JSONObject;
@@ -90,7 +91,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class RankingHelperTest extends NotificationTestCase {
+public class RankingHelperTest extends UiServiceTestCase {
private static final String PKG = "com.android.server.notification";
private static final int UID = 0;
private static final UserHandle USER = UserHandle.of(0);
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 97%
rename from services/tests/notification/src/com/android/server/notification/RateEstimatorTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java
index e354267..5d8d48f1 100644
--- a/services/tests/notification/src/com/android/server/notification/RateEstimatorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java
@@ -24,9 +24,11 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
+import com.android.server.UiServiceTestCase;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class RateEstimatorTest extends NotificationTestCase {
+public class RateEstimatorTest extends UiServiceTestCase {
private long mTestStartTime;
private RateEstimator mEstimator;
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..9564ab9
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
@@ -0,0 +1,332 @@
+/*
+ * 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.filters.FlakyTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.UiServiceTestCase;
+
+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 UiServiceTestCase {
+
+ 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
+ @FlakyTest
+ 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
+ @FlakyTest
+ 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..17fed83
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleConditionProviderTest.java
@@ -0,0 +1,344 @@
+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 com.android.server.UiServiceTestCase;
+
+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 UiServiceTestCase {
+
+ 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 98%
rename from services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 07b21fb..88c6fcf 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -32,7 +32,6 @@
import android.service.notification.StatusBarNotification;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Slog;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -46,10 +45,12 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import com.android.server.UiServiceTestCase;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class SnoozeHelperTest extends NotificationTestCase {
+public class SnoozeHelperTest extends UiServiceTestCase {
private static final String TEST_CHANNEL_ID = "test_channel_id";
@Mock SnoozeHelper.Callback mCallback;
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 97%
rename from services/tests/notification/src/com/android/server/notification/ValidateNotificationPeopleTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
index 4ac0c65..58f0ded 100644
--- a/services/tests/notification/src/com/android/server/notification/ValidateNotificationPeopleTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
@@ -30,9 +30,11 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertEquals;
+import com.android.server.UiServiceTestCase;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class ValidateNotificationPeopleTest extends NotificationTestCase {
+public class ValidateNotificationPeopleTest extends UiServiceTestCase {
@Test
public void testNoExtra() throws Exception {
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 97%
rename from services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java
rename to services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 8ac6481..0c7397a 100644
--- a/services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -32,6 +32,8 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import com.android.server.UiServiceTestCase;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -41,7 +43,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class ZenModeHelperTest extends NotificationTestCase {
+public class ZenModeHelperTest extends UiServiceTestCase {
@Mock ConditionProviders mConditionProviders;
private TestableLooper mTestableLooper;
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
new file mode 100644
index 0000000..ce328c2
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
@@ -0,0 +1,214 @@
+package com.android.server.slice;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.slice.ISliceListener;
+import android.app.slice.Slice;
+import android.app.slice.SliceProvider;
+import android.app.slice.SliceSpec;
+import android.content.ContentProvider;
+import android.content.IContentProvider;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class PinnedSliceStateTest extends UiServiceTestCase {
+
+ private static final String AUTH = "my.authority";
+ private static final Uri TEST_URI = Uri.parse("content://" + AUTH + "/path");
+
+ private static final SliceSpec[] FIRST_SPECS = new SliceSpec[]{
+ new SliceSpec("spec1", 3),
+ new SliceSpec("spec2", 3),
+ new SliceSpec("spec3", 2),
+ new SliceSpec("spec4", 1),
+ };
+
+ private static final SliceSpec[] SECOND_SPECS = new SliceSpec[]{
+ new SliceSpec("spec2", 1),
+ new SliceSpec("spec3", 2),
+ new SliceSpec("spec4", 3),
+ new SliceSpec("spec5", 4),
+ };
+
+ private SliceManagerService mSliceService;
+ private PinnedSliceState mPinnedSliceManager;
+ private IContentProvider mIContentProvider;
+ private ContentProvider mContentProvider;
+
+ @Before
+ public void setup() {
+ mSliceService = mock(SliceManagerService.class);
+ when(mSliceService.getLock()).thenReturn(new Object());
+ when(mSliceService.getContext()).thenReturn(mContext);
+ when(mSliceService.getHandler()).thenReturn(new Handler(TestableLooper.get(this).getLooper()));
+ mContentProvider = mock(ContentProvider.class);
+ mIContentProvider = mock(IContentProvider.class);
+ when(mContentProvider.getIContentProvider()).thenReturn(mIContentProvider);
+ mContext.getContentResolver().addProvider(AUTH, mContentProvider);
+ mPinnedSliceManager = new PinnedSliceState(mSliceService, TEST_URI);
+ }
+
+ @Test
+ public void testMergeSpecs() {
+ // No annotations to start.
+ assertNull(mPinnedSliceManager.getSpecs());
+
+ mPinnedSliceManager.mergeSpecs(FIRST_SPECS);
+ assertArrayEquals(FIRST_SPECS, mPinnedSliceManager.getSpecs());
+
+ mPinnedSliceManager.mergeSpecs(SECOND_SPECS);
+ assertArrayEquals(new SliceSpec[]{
+ // spec1 is gone because it's not in the second set.
+ new SliceSpec("spec2", 1), // spec2 is 1 because it's smaller in the second set.
+ new SliceSpec("spec3", 2), // spec3 is the same in both sets
+ new SliceSpec("spec4", 1), // spec4 is 1 because it's smaller in the first set.
+ // spec5 is gone because it's not in the first set.
+ }, mPinnedSliceManager.getSpecs());
+ }
+
+ @Test
+ public void testSendPinnedOnCreate() throws RemoteException {
+ // When created, a pinned message should be sent.
+ TestableLooper.get(this).processAllMessages();
+
+ verify(mIContentProvider).call(anyString(), eq(SliceProvider.METHOD_PIN), eq(null),
+ argThat(b -> {
+ assertEquals(TEST_URI, b.getParcelable(SliceProvider.EXTRA_BIND_URI));
+ return true;
+ }));
+ }
+
+ @Test
+ public void testSendUnpinnedOnDestroy() throws RemoteException {
+ TestableLooper.get(this).processAllMessages();
+ clearInvocations(mIContentProvider);
+
+ mPinnedSliceManager.destroy();
+ TestableLooper.get(this).processAllMessages();
+
+ verify(mIContentProvider).call(anyString(), eq(SliceProvider.METHOD_UNPIN), eq(null),
+ argThat(b -> {
+ assertEquals(TEST_URI, b.getParcelable(SliceProvider.EXTRA_BIND_URI));
+ return true;
+ }));
+ }
+
+ @Test
+ public void testPkgPin() {
+ assertFalse(mPinnedSliceManager.isPinned());
+
+ mPinnedSliceManager.pin("pkg", FIRST_SPECS);
+ assertTrue(mPinnedSliceManager.isPinned());
+
+ assertTrue(mPinnedSliceManager.unpin("pkg"));
+ assertFalse(mPinnedSliceManager.isPinned());
+ }
+
+ @Test
+ public void testMultiPkgPin() {
+ assertFalse(mPinnedSliceManager.isPinned());
+
+ mPinnedSliceManager.pin("pkg", FIRST_SPECS);
+ assertTrue(mPinnedSliceManager.isPinned());
+ mPinnedSliceManager.pin("pkg2", FIRST_SPECS);
+
+ assertFalse(mPinnedSliceManager.unpin("pkg"));
+ assertTrue(mPinnedSliceManager.unpin("pkg2"));
+ assertFalse(mPinnedSliceManager.isPinned());
+ }
+
+ @Test
+ public void testListenerPin() {
+ ISliceListener listener = mock(ISliceListener.class);
+ assertFalse(mPinnedSliceManager.isPinned());
+
+ mPinnedSliceManager.addSliceListener(listener, FIRST_SPECS);
+ assertTrue(mPinnedSliceManager.isPinned());
+
+ assertTrue(mPinnedSliceManager.removeSliceListener(listener));
+ assertFalse(mPinnedSliceManager.isPinned());
+ }
+
+ @Test
+ public void testMultiListenerPin() {
+ ISliceListener listener = mock(ISliceListener.class);
+ ISliceListener listener2 = mock(ISliceListener.class);
+ assertFalse(mPinnedSliceManager.isPinned());
+
+ mPinnedSliceManager.addSliceListener(listener, FIRST_SPECS);
+ assertTrue(mPinnedSliceManager.isPinned());
+ mPinnedSliceManager.addSliceListener(listener2, FIRST_SPECS);
+
+ assertFalse(mPinnedSliceManager.removeSliceListener(listener));
+ assertTrue(mPinnedSliceManager.removeSliceListener(listener2));
+ assertFalse(mPinnedSliceManager.isPinned());
+ }
+
+ @Test
+ public void testPkgListenerPin() {
+ ISliceListener listener = mock(ISliceListener.class);
+ assertFalse(mPinnedSliceManager.isPinned());
+
+ mPinnedSliceManager.addSliceListener(listener, FIRST_SPECS);
+ assertTrue(mPinnedSliceManager.isPinned());
+ mPinnedSliceManager.pin("pkg", FIRST_SPECS);
+
+ assertFalse(mPinnedSliceManager.removeSliceListener(listener));
+ assertTrue(mPinnedSliceManager.unpin("pkg"));
+ assertFalse(mPinnedSliceManager.isPinned());
+ }
+
+ @Test
+ public void testBind() throws RemoteException {
+ TestableLooper.get(this).processAllMessages();
+ clearInvocations(mIContentProvider);
+
+ ISliceListener listener = mock(ISliceListener.class);
+ Slice s = new Slice.Builder(TEST_URI).build();
+ Bundle b = new Bundle();
+ b.putParcelable(SliceProvider.EXTRA_SLICE, s);
+ when(mIContentProvider.call(anyString(), eq(SliceProvider.METHOD_SLICE), eq(null),
+ any())).thenReturn(b);
+
+ assertFalse(mPinnedSliceManager.isPinned());
+
+ mPinnedSliceManager.addSliceListener(listener, FIRST_SPECS);
+
+ mPinnedSliceManager.onChange();
+ TestableLooper.get(this).processAllMessages();
+
+ verify(mIContentProvider).call(anyString(), eq(SliceProvider.METHOD_SLICE), eq(null),
+ argThat(bundle -> {
+ assertEquals(TEST_URI, bundle.getParcelable(SliceProvider.EXTRA_BIND_URI));
+ return true;
+ }));
+ verify(listener).onSliceUpdated(eq(s));
+ }
+}
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
new file mode 100644
index 0000000..fe9ea7a
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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 static android.content.ContentProvider.maybeAddUserId;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+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.AppOpsManager;
+import android.app.slice.ISliceListener;
+import android.app.slice.SliceSpec;
+import android.content.pm.PackageManagerInternal;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.server.LocalServices;
+import com.android.server.UiServiceTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class SliceManagerServiceTest extends UiServiceTestCase {
+
+ private static final String AUTH = "com.android.services.uitests";
+ private static final Uri TEST_URI = maybeAddUserId(Uri.parse("content://" + AUTH + "/path"), 0);
+
+ private static final SliceSpec[] EMPTY_SPECS = new SliceSpec[]{
+ };
+
+ private SliceManagerService mService;
+ private PinnedSliceState mCreatedSliceState;
+
+ @Before
+ public void setup() {
+ LocalServices.addService(PackageManagerInternal.class, mock(PackageManagerInternal.class));
+ mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
+ mContext.getTestablePermissions().setPermission(TEST_URI, PERMISSION_GRANTED);
+
+ mService = spy(new SliceManagerService(mContext, TestableLooper.get(this).getLooper()));
+ mCreatedSliceState = mock(PinnedSliceState.class);
+ doReturn(mCreatedSliceState).when(mService).createPinnedSlice(eq(TEST_URI));
+ }
+
+ @After
+ public void teardown() {
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ }
+
+ @Test
+ public void testAddListenerCreatesPinned() throws RemoteException {
+ mService.addSliceListener(TEST_URI, "pkg", mock(ISliceListener.class), EMPTY_SPECS);
+ verify(mService, times(1)).createPinnedSlice(eq(TEST_URI));
+ }
+
+ @Test
+ public void testAddListenerCreatesOnePinned() throws RemoteException {
+ mService.addSliceListener(TEST_URI, "pkg", mock(ISliceListener.class), EMPTY_SPECS);
+ mService.addSliceListener(TEST_URI, "pkg", mock(ISliceListener.class), EMPTY_SPECS);
+ verify(mService, times(1)).createPinnedSlice(eq(TEST_URI));
+ }
+
+ @Test
+ public void testRemoveListenerDestroysPinned() throws RemoteException {
+ ISliceListener listener = mock(ISliceListener.class);
+ mService.addSliceListener(TEST_URI, "pkg", listener, EMPTY_SPECS);
+
+ when(mCreatedSliceState.removeSliceListener(eq(listener))).thenReturn(false);
+ mService.removeSliceListener(TEST_URI, "pkg", listener);
+ verify(mCreatedSliceState, never()).destroy();
+
+ when(mCreatedSliceState.removeSliceListener(eq(listener))).thenReturn(true);
+ mService.removeSliceListener(TEST_URI, "pkg", listener);
+ verify(mCreatedSliceState).destroy();
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testUnrecognizedThrows() throws RemoteException {
+ mService.removeSliceListener(TEST_URI, "pkg", mock(ISliceListener.class));
+ }
+
+ @Test
+ public void testAddPinCreatesPinned() throws RemoteException {
+ doReturn("pkg").when(mService).getDefaultHome(anyInt());
+
+ mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS);
+ mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS);
+ verify(mService, times(1)).createPinnedSlice(eq(TEST_URI));
+ }
+
+ @Test
+ public void testRemovePinDestroysPinned() throws RemoteException {
+ doReturn("pkg").when(mService).getDefaultHome(anyInt());
+
+ mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS);
+
+ when(mCreatedSliceState.unpin(eq("pkg"))).thenReturn(false);
+ mService.unpinSlice("pkg", TEST_URI);
+ verify(mCreatedSliceState, never()).destroy();
+
+ when(mCreatedSliceState.unpin(eq("pkg"))).thenReturn(true);
+ mService.unpinSlice("pkg", TEST_URI);
+ verify(mCreatedSliceState).destroy();
+ }
+
+}
\ No newline at end of file
diff --git a/services/usage/Android.bp b/services/usage/Android.bp
new file mode 100644
index 0000000..1064b6e
--- /dev/null
+++ b/services/usage/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+ name: "services.usage",
+ srcs: ["java/**/*.java"],
+ libs: ["services.core"],
+}
diff --git a/services/usage/Android.mk b/services/usage/Android.mk
deleted file mode 100644
index f1cbe98..0000000
--- a/services/usage/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services.usage
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,java)
-
-LOCAL_JAVA_LIBRARIES := services.core
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index ee11241..620922a 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;
@@ -45,6 +42,8 @@
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
/**
* Keeps track of recent active state changes in apps.
@@ -75,14 +74,13 @@
private static final String ATTR_SCREEN_IDLE = "screenIdleTime";
// Elapsed timebase time when app was last used
private static final String ATTR_ELAPSED_IDLE = "elapsedIdleTime";
+ // Elapsed timebase time when the app bucket was last predicted externally
+ private static final String ATTR_LAST_PREDICTED_TIME = "lastPredictedTime";
+ // The standby bucket for the app
private static final String ATTR_CURRENT_BUCKET = "appLimitBucket";
+ // The reason the app was put in the above bucket
private static final String ATTR_BUCKETING_REASON = "bucketReason";
- // State that was last informed to listeners, since boot
- private static final int STATE_UNINFORMED = 0;
- private static final int STATE_ACTIVE = 1;
- private static final int STATE_IDLE = 2;
-
// device on time = mElapsedDuration + (timeNow - mElapsedSnapshot)
private long mElapsedSnapshot; // Elapsed time snapshot when last write of mDeviceOnDuration
private long mElapsedDuration; // Total device on duration since device was "born"
@@ -95,12 +93,21 @@
private boolean mScreenOn;
- private static class AppUsageHistory {
+ static class AppUsageHistory {
+ // Debug
final byte[] recent = new byte[HISTORY_SIZE];
+ // Last used time using elapsed timebase
long lastUsedElapsedTime;
+ // Last used time using screen_on timebase
long lastUsedScreenTime;
- @StandbyBuckets int currentBucket;
+ // Last predicted time using elapsed timebase
+ long lastPredictedTime;
+ // Standby bucket
+ @UsageStatsManager.StandbyBuckets
+ int currentBucket;
+ // Reason for setting the standby bucket. TODO: Switch to int.
String bucketingReason;
+ // In-memory only, last bucket for which the listeners were informed
int lastInformedBucket;
}
@@ -190,14 +197,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 +213,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 +278,10 @@
appUsageHistory = new AppUsageHistory();
appUsageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime);
appUsageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
- appUsageHistory.currentBucket = AppStandby.STANDBY_BUCKET_NEVER;
- appUsageHistory.bucketingReason = REASON_DEFAULT;
+ appUsageHistory.lastPredictedTime = getElapsedTime(0);
+ appUsageHistory.currentBucket = UsageStatsManager.STANDBY_BUCKET_NEVER;
+ appUsageHistory.bucketingReason = UsageStatsManager.REASON_DEFAULT;
+ appUsageHistory.lastInformedBucket = -1;
userHistory.put(packageName, appUsageHistory);
}
return appUsageHistory;
@@ -289,13 +298,21 @@
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);
}
}
+ public AppUsageHistory getAppUsageHistory(String packageName, int userId,
+ long elapsedRealtime) {
+ ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
+ AppUsageHistory appUsageHistory =
+ getPackageHistory(userHistory, packageName, elapsedRealtime, true);
+ return appUsageHistory;
+ }
+
public void setAppStandbyBucket(String packageName, int userId, long elapsedRealtime,
int bucket, String reason) {
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
@@ -303,6 +320,9 @@
getPackageHistory(userHistory, packageName, elapsedRealtime, true);
appUsageHistory.currentBucket = bucket;
appUsageHistory.bucketingReason = reason;
+ if (reason.startsWith(UsageStatsManager.REASON_PREDICTED)) {
+ appUsageHistory.lastPredictedTime = getElapsedTime(elapsedRealtime);
+ }
if (DEBUG) {
Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket
+ ", reason=" + appUsageHistory.bucketingReason);
@@ -316,6 +336,16 @@
return appUsageHistory.currentBucket;
}
+ public Map<String, Integer> getAppStandbyBuckets(int userId, long elapsedRealtime) {
+ ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
+ int size = userHistory.size();
+ HashMap<String, Integer> buckets = new HashMap<>(size);
+ for (int i = 0; i < size; i++) {
+ buckets.put(userHistory.keyAt(i), userHistory.valueAt(i).currentBucket);
+ }
+ return buckets;
+ }
+
public String getAppStandbyReason(String packageName, int userId, long elapsedRealtime) {
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
AppUsageHistory appUsageHistory =
@@ -323,7 +353,7 @@
return appUsageHistory != null ? appUsageHistory.bucketingReason : null;
}
- private long getElapsedTime(long elapsedRealtime) {
+ public long getElapsedTime(long elapsedRealtime) {
return (elapsedRealtime - mElapsedSnapshot + mElapsedDuration);
}
@@ -333,12 +363,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;
}
@@ -432,16 +462,23 @@
Long.parseLong(parser.getAttributeValue(null, ATTR_ELAPSED_IDLE));
appUsageHistory.lastUsedScreenTime =
Long.parseLong(parser.getAttributeValue(null, ATTR_SCREEN_IDLE));
+ String lastPredictedTimeString = parser.getAttributeValue(null,
+ ATTR_LAST_PREDICTED_TIME);
+ if (lastPredictedTimeString != null) {
+ appUsageHistory.lastPredictedTime =
+ Long.parseLong(lastPredictedTimeString);
+ }
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;
}
+ appUsageHistory.lastInformedBucket = -1;
userHistory.put(packageName, appUsageHistory);
}
}
@@ -478,6 +515,8 @@
Long.toString(history.lastUsedElapsedTime));
xml.attribute(null, ATTR_SCREEN_IDLE,
Long.toString(history.lastUsedScreenTime));
+ xml.attribute(null, ATTR_LAST_PREDICTED_TIME,
+ Long.toString(history.lastPredictedTime));
xml.attribute(null, ATTR_CURRENT_BUCKET,
Integer.toString(history.currentBucket));
xml.attribute(null, ATTR_BUCKETING_REASON, history.bucketingReason);
@@ -513,6 +552,8 @@
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastUsedElapsedTime, idpw);
idpw.print(" lastUsedScreenOn=");
TimeUtils.formatDuration(screenOnTime - appUsageHistory.lastUsedScreenTime, idpw);
+ idpw.print(" lastPredictedTime=");
+ TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastPredictedTime, idpw);
idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
idpw.print(" bucket=" + appUsageHistory.currentBucket
+ " reason=" + appUsageHistory.bucketingReason);
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 3c099c2..46efbd0 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -16,15 +16,26 @@
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_PREDICTED;
+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;
@@ -73,6 +84,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
/**
* Manages the standby state of an app, listening to various events.
@@ -102,12 +114,15 @@
};
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
};
+ // Expiration time for predicted bucket
+ private static final long PREDICTION_TIMEOUT = 12 * ONE_HOUR;
+
// To name the lock for stack traces
static class Lock {}
@@ -370,30 +385,37 @@
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,
+ AppIdleHistory.AppUsageHistory app =
+ mAppIdleHistory.getAppUsageHistory(packageName,
userId, elapsedRealtime);
// If the bucket was forced by the developer, leave it alone
- if (AppStandby.REASON_FORCED.equals(bucketingReason)) {
+ if (REASON_FORCED.equals(app.bucketingReason)) {
continue;
}
+ boolean predictionLate = false;
// If the bucket was moved up due to usage, let the timeouts apply.
- if (AppStandby.REASON_USAGE.equals(bucketingReason)
- || AppStandby.REASON_TIMEOUT.equals(bucketingReason)) {
- int oldBucket = mAppIdleHistory.getAppStandbyBucket(packageName, userId,
- elapsedRealtime);
+ if (REASON_DEFAULT.equals(app.bucketingReason)
+ || REASON_USAGE.equals(app.bucketingReason)
+ || REASON_TIMEOUT.equals(app.bucketingReason)
+ || (predictionLate = predictionTimedOut(app, elapsedRealtime))) {
+ int oldBucket = app.currentBucket;
int newBucket = getBucketForLocked(packageName, userId,
elapsedRealtime);
if (DEBUG) {
Slog.d(TAG, " Old bucket=" + oldBucket
+ ", newBucket=" + newBucket);
}
- if (oldBucket < newBucket) {
+ if (oldBucket < newBucket || predictionLate) {
mAppIdleHistory.setAppStandbyBucket(packageName, userId,
- elapsedRealtime, newBucket, AppStandby.REASON_TIMEOUT);
+ elapsedRealtime, newBucket, REASON_TIMEOUT);
maybeInformListeners(packageName, userId, elapsedRealtime,
newBucket);
}
@@ -409,6 +431,14 @@
return true;
}
+ private boolean predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime) {
+ return app.bucketingReason != null
+ && app.bucketingReason.startsWith(REASON_PREDICTED)
+ && app.lastPredictedTime > 0
+ && mAppIdleHistory.getElapsedTime(elapsedRealtime)
+ - app.lastPredictedTime > PREDICTION_TIMEOUT;
+ }
+
private void maybeInformListeners(String packageName, int userId,
long elapsedRealtime, int bucket) {
synchronized (mAppIdleLock) {
@@ -742,16 +772,26 @@
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);
+ synchronized (mAppIdleLock) {
+ return mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime);
+ }
+ }
+
+ public Map<String, Integer> getAppStandbyBuckets(int userId, long elapsedRealtime) {
+ synchronized (mAppIdleLock) {
+ return mAppIdleHistory.getAppStandbyBuckets(userId, elapsedRealtime);
+ }
}
void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
String reason, long elapsedRealtime) {
- mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
- reason);
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
+ reason);
+ }
maybeInformListeners(packageName, userId, elapsedRealtime,
newBucket);
}
@@ -811,7 +851,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 +918,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/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 21b11b0..82f8001 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -164,6 +164,14 @@
}
@Override
+ public boolean isReservedSupported(String volumeUuid, String callingPackage) {
+ enforcePermission(Binder.getCallingUid(), callingPackage);
+
+ // TODO: implement as part of b/62024591
+ return false;
+ }
+
+ @Override
public long getTotalBytes(String volumeUuid, String callingPackage) {
// NOTE: No permissions required
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..15284d5 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;
@@ -68,7 +68,10 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
/**
* A service that collects, aggregates, and persists application usage data.
@@ -149,6 +152,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 +683,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 +716,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 +730,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);
@@ -726,6 +744,68 @@
}
@Override
+ public Map getAppStandbyBuckets(String callingPackageName, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ try {
+ userId = ActivityManager.getService().handleIncomingUser(
+ Binder.getCallingPid(), callingUid, userId, false, false,
+ "getAppStandbyBucket", null);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ if (!hasPermission(callingPackageName)) {
+ throw new SecurityException(
+ "Don't have permission to query app standby bucket");
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return mAppStandby.getAppStandbyBuckets(userId,
+ SystemClock.elapsedRealtime());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void setAppStandbyBuckets(Map appBuckets, int userId) {
+ getContext().enforceCallingPermission(Manifest.permission.CHANGE_APP_IDLE_STATE,
+ "No permission to change app standby state");
+
+ final int callingUid = Binder.getCallingUid();
+ try {
+ userId = ActivityManager.getService().handleIncomingUser(
+ Binder.getCallingPid(), callingUid, userId, false, true,
+ "setAppStandbyBucket", null);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ Map<String, Integer> buckets = (Map<String, Integer>) appBuckets;
+ for (Map.Entry<String, Integer> entry: buckets.entrySet()) {
+ String packageName = entry.getKey();
+ int bucket = entry.getValue();
+ if (bucket < UsageStatsManager.STANDBY_BUCKET_ACTIVE
+ || bucket > UsageStatsManager.STANDBY_BUCKET_NEVER) {
+ throw new IllegalArgumentException(
+ "Cannot set the standby bucket to " + bucket);
+ }
+ // 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,
+ UsageStatsManager.REASON_PREDICTED + ":" + callingUid,
+ elapsedRealtime);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
public void whitelistAppTemporarily(String packageName, long duration, int userId)
throws RemoteException {
StringBuilder reason = new StringBuilder(32);
diff --git a/services/usb/Android.bp b/services/usb/Android.bp
new file mode 100644
index 0000000..0cd9ac3
--- /dev/null
+++ b/services/usb/Android.bp
@@ -0,0 +1,14 @@
+java_library_static {
+ name: "services.usb",
+ srcs: ["java/**/*.java"],
+
+ libs: [
+ "services.core",
+ "android.hidl.manager-V1.0-java",
+ ],
+
+ static_libs: [
+ "android.hardware.usb-V1.0-java",
+ "android.hardware.usb-V1.1-java",
+ ],
+}
diff --git a/services/usb/Android.mk b/services/usb/Android.mk
deleted file mode 100644
index 55bfccf..0000000
--- a/services/usb/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services.usb
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,java)
-
-LOCAL_JAVA_LIBRARIES := services.core \
-android.hidl.manager-V1.0-java
-
-LOCAL_STATIC_JAVA_LIBRARIES := android.hardware.usb-V1.0-java \
-android.hardware.usb-V1.1-java
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index dd2e192..7a352a4 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -28,19 +28,23 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.descriptors.UsbDescriptor;
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.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;
@@ -63,6 +67,128 @@
@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 CONNECT_BADPARSE = 1;
+ static final int CONNECT_BADDEVICE = 2;
+ 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 != DISCONNECT) {
+ pw.println(formatTime() + " Connect " + mDeviceAddress + " mode:" + mMode);
+ 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 dumpTree(IndentingPrintWriter pw) {
+ if (mMode != DISCONNECT) {
+ pw.println(formatTime() + " Connect " + mDeviceAddress + " mode:" + mMode);
+ 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);
+ }
+ }
+
+ void dumpList(IndentingPrintWriter pw) {
+ if (mMode != DISCONNECT) {
+ pw.println(formatTime() + " Connect " + mDeviceAddress + " mode:" + mMode);
+ UsbDescriptorParser parser = new UsbDescriptorParser(mDeviceAddress, mDescriptors);
+ StringBuilder stringBuilder = new StringBuilder();
+ TextReportCanvas canvas = new TextReportCanvas(parser, stringBuilder);
+ for (UsbDescriptor descriptor : parser.getDescriptors()) {
+ descriptor.report(canvas);
+ }
+ pw.println(stringBuilder.toString());
+
+ pw.println("isHeadset[in: " + parser.isInputHeadset()
+ + " , out: " + parser.isOutputHeadset() + "]");
+ } else {
+ pw.println(formatTime() + " Disconnect " + mDeviceAddress);
+ }
+ }
+
+ private static final int kDumpBytesPerLine = 16;
+
+ void dumpRaw(IndentingPrintWriter pw) {
+ if (mMode != DISCONNECT) {
+ pw.println(formatTime() + " Connect " + mDeviceAddress + " mode:" + mMode);
+ int length = mDescriptors.length;
+ pw.println("Raw Descriptors " + length + " bytes");
+ int dataOffset = 0;
+ for (int line = 0; line < length / kDumpBytesPerLine; line++) {
+ StringBuilder sb = new StringBuilder();
+ for (int offset = 0; offset < kDumpBytesPerLine; offset++) {
+ sb.append("0x")
+ .append(String.format("0x%02X", mDescriptors[dataOffset++]))
+ .append(" ");
+ }
+ pw.println(sb.toString());
+ }
+
+ // remainder
+ StringBuilder sb = new StringBuilder();
+ while (dataOffset < length) {
+ sb.append("0x")
+ .append(String.format("0x%02X", mDescriptors[dataOffset++]))
+ .append(" ");
+ }
+ pw.println(sb.toString());
+ } else {
+ pw.println(formatTime() + " Disconnect " + mDeviceAddress);
+ }
+ }
+ }
+
+ /*
+ * UsbHostManager
+ */
public UsbHostManager(Context context, UsbAlsaManager alsaManager,
UsbSettingsManager settingsManager) {
mContext = context;
@@ -124,6 +250,19 @@
}
+ 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.DISCONNECT) {
+ mLastConnect = rec;
+ }
+ }
+
/* Called from JNI in monitorUsbHostBus() to report new USB devices
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.
@@ -155,27 +294,41 @@
if (parser.parseDescriptors(descriptors)) {
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(newDevice);
+ if (newDevice == null) {
+ Slog.e(TAG, "Couldn't create UsbDevice object.");
+ // Tracking
+ addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADDEVICE,
+ parser.getRawDescriptors());
} else {
- getCurrentUserSettings().deviceAttachedForFixedHandler(newDevice,
- usbDeviceConnectionHandler);
+ 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(newDevice);
+ } else {
+ getCurrentUserSettings().deviceAttachedForFixedHandler(newDevice,
+ usbDeviceConnectionHandler);
+ }
+
+ // 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());
}
-
- // Headset?
- boolean isInputHeadset = parser.isInputHeadset();
- boolean isOutputHeadset = parser.isOutputHeadset();
- Slog.i(TAG, "---- isHeadset[in: " + isInputHeadset
- + " , out: " + isOutputHeadset + "]");
-
- mUsbAlsaManager.usbDeviceAdded(newDevice, isInputHeadset, isOutputHeadset);
} else {
Slog.e(TAG, "Error parsing USB device descriptors for " + deviceAddress);
+ // Tracking
+ addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADPARSE,
+ parser.getRawDescriptors());
return false;
}
}
@@ -196,6 +349,9 @@
mUsbAlsaManager.usbDeviceRemoved(device);
mSettingsManager.usbDeviceRemoved(device);
getCurrentUserSettings().usbDeviceRemoved(device);
+
+ // Tracking
+ addConnectionRecord(deviceAddress, ConnectionRecord.DISCONNECT, null);
}
}
}
@@ -237,7 +393,11 @@
}
}
- public void dump(IndentingPrintWriter pw) {
+ /**
+ * Dump out various information about the state of USB device connections.
+ *
+ */
+ public void dump(IndentingPrintWriter pw, String[] args) {
pw.println("USB Host State:");
synchronized (mHandlerLock) {
if (mUsbDeviceConnectionHandler != null) {
@@ -249,32 +409,38 @@
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();
-
- UsbDescriptorParser parser = new UsbDescriptorParser(device.getDeviceName());
- if (parser.parseDevice()) {
- UsbDescriptorsTree descriptorTree = new UsbDescriptorsTree();
- descriptorTree.parse(parser);
-
- descriptorTree.report(new TextReportCanvas(parser, stringBuilder));
-
- stringBuilder.append("isHeadset[in: " + parser.isInputHeadset()
- + " , out: " + parser.isOutputHeadset() + "]");
- } else {
- stringBuilder.append("Error Parsing USB Descriptors");
- }
- pw.println(stringBuilder.toString());
- }
+ // Connections
+ pw.println("" + mNumConnects + " total connects/disconnects");
+ pw.println("Last " + mConnections.size() + " connections/disconnections");
+ for (ConnectionRecord rec : mConnections) {
+ rec.dumpShort(pw);
}
+
}
mUsbAlsaManager.dump(pw);
}
+ /**
+ * Dump various descriptor data.
+ */
+ public void dumpDescriptors(IndentingPrintWriter pw, String[] args) {
+ if (mLastConnect != null) {
+ pw.println("Last Connected USB Device:");
+ if (args.length <= 1 || args[1].equals("-dump-short")) {
+ mLastConnect.dumpShort(pw);
+ } else if (args[1].equals("-dump-tree")) {
+ mLastConnect.dumpTree(pw);
+ } else if (args[1].equals("-dump-list")) {
+ mLastConnect.dumpList(pw);
+ } else if (args[1].equals("-dump-raw")) {
+ mLastConnect.dumpRaw(pw);
+ }
+ } else {
+ pw.println("No USB Devices have been connected.");
+ }
+ }
+
private native void monitorUsbHostBus();
private native ParcelFileDescriptor nativeOpenDevice(String deviceAddress);
}
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 17de83f..8554cf7 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -496,7 +496,7 @@
mDeviceManager.dump(pw);
}
if (mHostManager != null) {
- mHostManager.dump(pw);
+ mHostManager.dump(pw, args);
}
if (mPortManager != null) {
mPortManager.dump(pw);
@@ -504,7 +504,7 @@
mAlsaManager.dump(pw);
mSettingsManager.dump(pw);
- } else if (args.length == 4 && "set-port-roles".equals(args[0])) {
+ } else if ("set-port-roles".equals(args[0]) && args.length == 4) {
final String portId = args[1];
final int powerRole;
switch (args[2]) {
@@ -546,7 +546,7 @@
pw.println();
mPortManager.dump(pw);
}
- } else if (args.length == 3 && "add-port".equals(args[0])) {
+ } else if ("add-port".equals(args[0]) && args.length == 3) {
final String portId = args[1];
final int supportedModes;
switch (args[2]) {
@@ -571,7 +571,7 @@
pw.println();
mPortManager.dump(pw);
}
- } else if (args.length == 5 && "connect-port".equals(args[0])) {
+ } else if ("connect-port".equals(args[0]) && args.length == 5) {
final String portId = args[1];
final int mode;
final boolean canChangeMode = args[2].endsWith("?");
@@ -618,30 +618,32 @@
pw.println();
mPortManager.dump(pw);
}
- } else if (args.length == 2 && "disconnect-port".equals(args[0])) {
+ } else if ("disconnect-port".equals(args[0]) && args.length == 2) {
final String portId = args[1];
if (mPortManager != null) {
mPortManager.disconnectSimulatedPort(portId, pw);
pw.println();
mPortManager.dump(pw);
}
- } else if (args.length == 2 && "remove-port".equals(args[0])) {
+ } else if ("remove-port".equals(args[0]) && args.length == 2) {
final String portId = args[1];
if (mPortManager != null) {
mPortManager.removeSimulatedPort(portId, pw);
pw.println();
mPortManager.dump(pw);
}
- } else if (args.length == 1 && "reset".equals(args[0])) {
+ } else if ("reset".equals(args[0]) && args.length == 1) {
if (mPortManager != null) {
mPortManager.resetSimulation(pw);
pw.println();
mPortManager.dump(pw);
}
- } else if (args.length == 1 && "ports".equals(args[0])) {
+ } else if ("ports".equals(args[0]) && args.length == 1) {
if (mPortManager != null) {
mPortManager.dump(pw);
}
+ } else if ("dump-descriptors".equals(args[0])) {
+ mHostManager.dumpDescriptors(pw, args);
} else {
pw.println("Dump current USB state or issue command:");
pw.println(" ports");
@@ -678,6 +680,12 @@
pw.println(" dumpsys usb add-port \"matrix\" ufp");
pw.println(" dumpsys usb connect-port \"matrix\" ufp sink device");
pw.println(" dumpsys usb reset");
+ pw.println();
+ pw.println("Example USB device descriptors:");
+ pw.println(" dumpsys usb dump-descriptors -dump-short");
+ pw.println(" dumpsys usb dump-descriptors -dump-tree");
+ pw.println(" dumpsys usb dump-descriptors -dump-list");
+ pw.println(" dumpsys usb dump-descriptors -dump-raw");
}
} finally {
Binder.restoreCallingIdentity(ident);
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 993778f..639aa4e 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
@@ -17,6 +17,7 @@
import android.hardware.usb.UsbConfiguration;
import android.hardware.usb.UsbInterface;
+import android.util.Log;
import com.android.server.usb.descriptors.report.ReportCanvas;
@@ -29,6 +30,7 @@
*/
public final class UsbConfigDescriptor extends UsbDescriptor {
private static final String TAG = "UsbConfigDescriptor";
+ private static final boolean DEBUG = false;
private int mTotalLength; // 2:2 Total length in bytes of data returned
private byte mNumInterfaces; // 4:1 Number of Interfaces
@@ -77,10 +79,16 @@
}
UsbConfiguration toAndroid(UsbDescriptorParser parser) {
+ if (DEBUG) {
+ Log.d(TAG, " toAndroid()");
+ }
String name = parser.getDescriptorString(mConfigIndex);
UsbConfiguration config = new
UsbConfiguration(mConfigValue, name, mAttribs, mMaxPower);
UsbInterface[] interfaces = new UsbInterface[mInterfaceDescriptors.size()];
+ if (DEBUG) {
+ Log.d(TAG, " " + mInterfaceDescriptors.size() + " interfaces.");
+ }
for (int index = 0; index < mInterfaceDescriptors.size(); index++) {
interfaces[index] = mInterfaceDescriptors.get(index).toAndroid(parser);
}
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 6c6bd01..7a1e9e2 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -26,13 +26,13 @@
*/
public final class UsbDescriptorParser {
private static final String TAG = "UsbDescriptorParser";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
private final String mDeviceAddr;
// Descriptor Objects
private static final int DESCRIPTORS_ALLOC_SIZE = 128;
- private ArrayList<UsbDescriptor> mDescriptors = new ArrayList<UsbDescriptor>();
+ private final ArrayList<UsbDescriptor> mDescriptors;
private UsbDeviceDescriptor mDeviceDescriptor;
private UsbConfigDescriptor mCurConfigDescriptor;
@@ -45,6 +45,28 @@
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() {
@@ -196,8 +218,6 @@
if (DEBUG) {
Log.d(TAG, "parseDescriptors() - start");
}
- // This will allow us to (probably) alloc mDescriptors just once.
- mDescriptors = new ArrayList<UsbDescriptor>(DESCRIPTORS_ALLOC_SIZE);
ByteStream stream = new ByteStream(descriptors);
while (stream.available() > 0) {
@@ -241,7 +261,7 @@
? parseDescriptors(rawDescriptors) : false;
}
- private byte[] getRawDescriptors() {
+ public byte[] getRawDescriptors() {
return getRawDescriptors_native(mDeviceAddr);
}
@@ -269,10 +289,15 @@
*/
public UsbDevice toAndroidUsbDevice() {
if (mDeviceDescriptor == null) {
+ Log.e(TAG, "toAndroidUsbDevice() ERROR - No Device Descriptor");
return null;
}
- return mDeviceDescriptor.toAndroid(this);
+ UsbDevice device = mDeviceDescriptor.toAndroid(this);
+ if (device == null) {
+ Log.e(TAG, "toAndroidUsbDevice() ERROR Creating Device");
+ }
+ return device;
}
/**
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 8e7f0fd..e31e3a3 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
@@ -17,6 +17,7 @@
import android.hardware.usb.UsbConfiguration;
import android.hardware.usb.UsbDevice;
+import android.util.Log;
import com.android.server.usb.descriptors.report.ReportCanvas;
import com.android.server.usb.descriptors.report.UsbStrings;
@@ -30,6 +31,7 @@
*/
public final class UsbDeviceDescriptor extends UsbDescriptor {
private static final String TAG = "UsbDeviceDescriptor";
+ private static final boolean DEBUG = false;
public static final int USBSPEC_1_0 = 0x0100;
public static final int USBSPEC_1_1 = 0x0110;
@@ -113,19 +115,30 @@
* @hide
*/
public UsbDevice toAndroid(UsbDescriptorParser parser) {
+ if (DEBUG) {
+ Log.d(TAG, "toAndroid()");
+ }
+
String mfgName = parser.getDescriptorString(mMfgIndex);
String prodName = parser.getDescriptorString(mProductIndex);
+ if (DEBUG) {
+ Log.d(TAG, " mfgName:" + mfgName + " prodName:" + prodName);
+ }
// Create version string in "%.%" format
String versionString =
Integer.toString(mDeviceRelease >> 8) + "." + (mDeviceRelease & 0xFF);
String serialStr = parser.getDescriptorString(mSerialNum);
+ if (DEBUG) {
+ Log.d(TAG, " versionString:" + versionString + " serialStr:" + serialStr);
+ }
UsbDevice device = new UsbDevice(parser.getDeviceAddr(), mVendorID, mProductID,
mDevClass, mDevSubClass,
mProtocol, mfgName, prodName,
versionString, serialStr);
UsbConfiguration[] configs = new UsbConfiguration[mConfigDescriptors.size()];
+ Log.d(TAG, " " + configs.length + " configs");
for (int index = 0; index < mConfigDescriptors.size(); index++) {
configs[index] = mConfigDescriptors.get(index).toAndroid(parser);
}
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 1130238..4da31ea 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
@@ -16,6 +16,7 @@
package com.android.server.usb.descriptors;
import android.hardware.usb.UsbEndpoint;
+import android.util.Log;
import com.android.server.usb.descriptors.report.ReportCanvas;
@@ -26,6 +27,7 @@
*/
public class UsbEndpointDescriptor extends UsbDescriptor {
private static final String TAG = "UsbEndpointDescriptor";
+ private static final boolean DEBUG = false;
public static final int MASK_ENDPOINT_ADDRESS = 0b000000000001111;
public static final int MASK_ENDPOINT_DIRECTION = (byte) 0b0000000010000000;
@@ -108,6 +110,12 @@
}
/* package */ UsbEndpoint toAndroid(UsbDescriptorParser parser) {
+ if (DEBUG) {
+ Log.d(TAG, "toAndroid() type:"
+ + Integer.toHexString(mAttributes & MASK_ATTRIBS_TRANSTYPE)
+ + " sync:" + Integer.toHexString(mAttributes & MASK_ATTRIBS_SYNCTYPE)
+ + " usage:" + Integer.toHexString(mAttributes & MASK_ATTRIBS_USEAGE));
+ }
return new UsbEndpoint(mEndpointAddress, mAttributes, mPacketSize, mInterval);
}
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 d87b1af..632e3dc 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
@@ -17,6 +17,7 @@
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
+import android.util.Log;
import com.android.server.usb.descriptors.report.ReportCanvas;
import com.android.server.usb.descriptors.report.UsbStrings;
@@ -30,6 +31,7 @@
*/
public class UsbInterfaceDescriptor extends UsbDescriptor {
private static final String TAG = "UsbInterfaceDescriptor";
+ private static final boolean DEBUG = false;
protected int mInterfaceNumber; // 2:1 Number of Interface
protected byte mAlternateSetting; // 3:1 Value used to select alternative setting
@@ -93,6 +95,11 @@
}
UsbInterface toAndroid(UsbDescriptorParser parser) {
+ if (DEBUG) {
+ Log.d(TAG, "toAndroid() class:" + Integer.toHexString(mUsbClass)
+ + " subclass:" + Integer.toHexString(mUsbSubclass)
+ + " " + mEndpointDescriptors.size() + " endpoints.");
+ }
String name = parser.getDescriptorString(mDescrIndex);
UsbInterface ntrface = new UsbInterface(
mInterfaceNumber, mAlternateSetting, name, mUsbClass, mUsbSubclass, mProtocol);
diff --git a/services/voiceinteraction/Android.bp b/services/voiceinteraction/Android.bp
new file mode 100644
index 0000000..390406f
--- /dev/null
+++ b/services/voiceinteraction/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+ name: "services.voiceinteraction",
+ srcs: ["java/**/*.java"],
+ libs: ["services.core"],
+}
diff --git a/services/voiceinteraction/Android.mk b/services/voiceinteraction/Android.mk
deleted file mode 100644
index c9e5dd0..0000000
--- a/services/voiceinteraction/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := services.voiceinteraction
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,java)
-
-LOCAL_JAVA_LIBRARIES := services.core
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
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 2d93da9..c0685f9 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -75,7 +75,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;
-import java.util.TreeSet;
/**
* SystemService that publishes an IVoiceInteractionManagerService.
@@ -442,11 +441,11 @@
mImpl.shutdownLocked();
}
if (hasComponent) {
- mImpl = new VoiceInteractionManagerServiceImpl(mContext,
- UiThread.getHandler(), this, mCurUser, serviceComponent);
+ setImplLocked(new VoiceInteractionManagerServiceImpl(mContext,
+ UiThread.getHandler(), this, mCurUser, serviceComponent));
mImpl.startLocked();
} else {
- mImpl = null;
+ setImplLocked(null);
}
}
}
@@ -1177,6 +1176,12 @@
}
}
+ private void setImplLocked(VoiceInteractionManagerServiceImpl impl) {
+ mImpl = impl;
+ mAmInternal.notifyActiveVoiceInteractionServiceChanged(
+ getActiveServiceComponentName());
+ }
+
class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler) {
super(handler);
@@ -1219,7 +1224,7 @@
unloadAllKeyphraseModels();
if (mImpl != null) {
mImpl.shutdownLocked();
- mImpl = null;
+ setImplLocked(null);
}
setCurInteractor(null, userHandle);
setCurRecognizer(null, userHandle);
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..dec7b76 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -21,6 +21,7 @@
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -143,6 +144,9 @@
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 String SESSION_HANDOVER_FAILED = "CS.haF";
private static final int MSG_ADD_CONNECTION_SERVICE_ADAPTER = 1;
private static final int MSG_CREATE_CONNECTION = 2;
@@ -172,6 +176,9 @@
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 final int MSG_HANDOVER_FAILED = 32;
private static Connection sNullConnection;
@@ -275,6 +282,22 @@
}
@Override
+ public void handoverFailed(String callId, ConnectionRequest request, int reason,
+ Session.Info sessionInfo) {
+ Log.startSession(sessionInfo, SESSION_HANDOVER_FAILED);
+ try {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = request;
+ args.arg3 = Log.createSubsession();
+ args.arg4 = reason;
+ mHandler.obtainMessage(MSG_HANDOVER_FAILED, args).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
public void abort(String callId, Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_ABORT);
try {
@@ -591,6 +614,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()) {
@@ -723,6 +766,36 @@
}
break;
}
+ case MSG_HANDOVER_FAILED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Log.continueSession((Session) args.arg3, SESSION_HANDLER +
+ SESSION_HANDOVER_FAILED);
+ try {
+ final String id = (String) args.arg1;
+ final ConnectionRequest request = (ConnectionRequest) args.arg2;
+ final int reason = (int) args.arg4;
+ if (!mAreAccountsInitialized) {
+ Log.d(this, "Enqueueing pre-init request %s", id);
+ mPreInitializationConnectionRequests.add(
+ new android.telecom.Logging.Runnable(
+ SESSION_HANDLER
+ + SESSION_HANDOVER_FAILED + ".pICR",
+ null /*lock*/) {
+ @Override
+ public void loggedRun() {
+ handoverFailed(id, request, reason);
+ }
+ }.prepare());
+ } else {
+ Log.i(this, "createConnectionFailed %s", id);
+ handoverFailed(id, request, reason);
+ }
+ } finally {
+ args.recycle();
+ Log.endSession();
+ }
+ break;
+ }
case MSG_ABORT: {
SomeArgs args = (SomeArgs) msg.obj;
Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_ABORT);
@@ -1012,6 +1085,12 @@
}
break;
}
+ case MSG_CONNECTION_SERVICE_FOCUS_GAINED:
+ onConnectionServiceFocusGained();
+ break;
+ case MSG_CONNECTION_SERVICE_FOCUS_LOST:
+ onConnectionServiceFocusLost();
+ break;
default:
break;
}
@@ -1371,9 +1450,20 @@
isIncoming,
isUnknown);
- Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
- : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
- : onCreateOutgoingConnection(callManagerAccount, request);
+ Connection connection = null;
+ if (getApplicationContext().getApplicationInfo().targetSdkVersion >
+ Build.VERSION_CODES.O_MR1 && request.getExtras() != null &&
+ request.getExtras().getBoolean(TelecomManager.EXTRA_IS_HANDOVER,false)) {
+ if (!isIncoming) {
+ connection = onCreateOutgoingHandoverConnection(callManagerAccount, request);
+ } else {
+ connection = onCreateIncomingHandoverConnection(callManagerAccount, request);
+ }
+ } 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(
@@ -1442,6 +1532,13 @@
}
}
+ private void handoverFailed(final String callId, final ConnectionRequest request,
+ int reason) {
+
+ Log.i(this, "handoverFailed %s", callId);
+ onHandoverFailed(request, reason);
+ }
+
/**
* Called by Telecom when the creation of a new Connection has completed and it is now added
* to Telecom.
@@ -1863,6 +1960,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 +2243,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/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 74b9465..fcfc593 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -964,6 +964,9 @@
if (hasCapabilities(CAPABILITY_SIM_SUBSCRIPTION)) {
sb.append("SimSub ");
}
+ if (hasCapabilities(CAPABILITY_RTT)) {
+ sb.append("Rtt");
+ }
return sb.toString();
}
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..3d04bfc 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -100,4 +100,11 @@
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);
+
+ void handoverFailed(String callId, in ConnectionRequest request,
+ int error, 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 69371a1..ead8849 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -735,6 +735,13 @@
public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
/**
+ * Flag specifying whether the {@link android.telephony.SignalStrength} is shown in the SIM
+ * Status screen. The default value is true.
+ */
+ public static final String KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL =
+ "show_signal_strength_in_sim_status_bool";
+
+ /**
* Flag specifying whether an additional (client initiated) intent needs to be sent on System
* update
*/
@@ -989,6 +996,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.
@@ -1296,6 +1309,19 @@
*/
public static final String KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL = "allow_hold_in_ims_call";
+
+ /**
+ * Flag indicating whether the carrier always wants to play an "on-hold" tone when a call has
+ * been remotely held.
+ * <p>
+ * When {@code true}, if the IMS stack indicates that the call session has been held, a signal
+ * will be sent from Telephony to play an audible "on-hold" tone played to the user.
+ * When {@code false}, a hold tone will only be played if the audio session becomes inactive.
+ * @hide
+ */
+ public static final String KEY_ALWAYS_PLAY_REMOTE_HOLD_TONE_BOOL =
+ "always_play_remote_hold_tone_bool";
+
/**
* When true, indicates that adding a call is disabled when there is an ongoing video call
* or when there is an ongoing call on wifi which was downgraded from video and VoWifi is
@@ -1634,6 +1660,11 @@
"show_ims_registration_status_bool";
/**
+ * Flag indicating whether the carrier supports RTT over IMS.
+ */
+ public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
+
+ /**
* The flag to disable the popup dialog which warns the user of data charges.
* @hide
*/
@@ -1692,6 +1723,7 @@
static {
sDefaults = new PersistableBundle();
sDefaults.putBoolean(KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL, true);
+ sDefaults.putBoolean(KEY_ALWAYS_PLAY_REMOTE_HOLD_TONE_BOOL, false);
sDefaults.putBoolean(KEY_ADDITIONAL_CALL_SETTING_BOOL, true);
sDefaults.putBoolean(KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL, false);
sDefaults.putBoolean(KEY_ALLOW_LOCAL_DTMF_TONES_BOOL, true);
@@ -1768,6 +1800,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_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL, true);
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, "");
@@ -1963,10 +1996,12 @@
sDefaults.putStringArray(KEY_NON_ROAMING_OPERATOR_STRING_ARRAY, null);
sDefaults.putStringArray(KEY_ROAMING_OPERATOR_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false);
+ sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false);
sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
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/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index fdedf75..7ab75f5 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -390,112 +390,6 @@
}
/**
- * Send a text based SMS with messaging options.
- *
- * @param destinationAddress the address to send the message to
- * @param scAddress is the service center address or null to use
- * the current default SMSC
- * @param text the body of the message to send
- * @param sentIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is successfully sent, or failed.
- * The result code will be <code>Activity.RESULT_OK</code> for success,
- * or one of these errors:<br>
- * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
- * <code>RESULT_ERROR_RADIO_OFF</code><br>
- * <code>RESULT_ERROR_NULL_PDU</code><br>
- * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
- * the extra "errorCode" containing a radio technology specific value,
- * generally only useful for troubleshooting.<br>
- * The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applications,
- * which cause smaller number of SMS to be sent in checking period.
- * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is delivered to the recipient. The
- * raw pdu of the status report is in the extended data ("pdu").
- * @param priority Priority level of the message
- * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
- * ---------------------------------
- * PRIORITY | Level of Priority
- * ---------------------------------
- * '00' | Normal
- * '01' | Interactive
- * '10' | Urgent
- * '11' | Emergency
- * ----------------------------------
- * Any Other values included Negative considered as Invalid Priority Indicator of the message.
- * @param expectMore is a boolean to indicate the sending messages through same link or not.
- * @param validityPeriod Validity Period of the message in mins.
- * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
- * Validity Period(Minimum) -> 5 mins
- * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
- * Any Other values included Negative considered as Invalid Validity Period of the message.
- *
- * @throws IllegalArgumentException if destinationAddress or text are empty
- * {@hide}
- */
- public void sendTextMessage(
- String destinationAddress, String scAddress, String text,
- PendingIntent sentIntent, PendingIntent deliveryIntent,
- int priority, boolean expectMore, int validityPeriod) {
- sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
- true /* persistMessage*/, priority, expectMore, validityPeriod);
- }
-
- private void sendTextMessageInternal(
- String destinationAddress, String scAddress, String text,
- PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage,
- int priority, boolean expectMore, int validityPeriod) {
- if (TextUtils.isEmpty(destinationAddress)) {
- throw new IllegalArgumentException("Invalid destinationAddress");
- }
-
- if (TextUtils.isEmpty(text)) {
- throw new IllegalArgumentException("Invalid message body");
- }
-
- if (priority < 0x00 || priority > 0x03) {
- throw new IllegalArgumentException("Invalid priority");
- }
-
- if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) {
- throw new IllegalArgumentException("Invalid validity period");
- }
-
- try {
- ISms iccISms = getISmsServiceOrThrow();
- if (iccISms != null) {
- iccISms.sendTextForSubscriberWithOptions(getSubscriptionId(),
- ActivityThread.currentPackageName(), destinationAddress, scAddress, text,
- sentIntent, deliveryIntent, persistMessage, priority, expectMore,
- validityPeriod);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- }
-
- /**
- * Send a text based SMS without writing it into the SMS Provider.
- *
- * <p>Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
- * privileges.
- * </p>
- *
- * @see #sendTextMessage(String, String, String, PendingIntent,
- * PendingIntent, int, boolean, int)
- * @hide
- */
- public void sendTextMessageWithoutPersisting(
- String destinationAddress, String scAddress, String text,
- PendingIntent sentIntent, PendingIntent deliveryIntent, int priority,
- boolean expectMore, int validityPeriod) {
- sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
- false /* persistMessage */, priority, expectMore, validityPeriod);
- }
-
- /**
- *
* Inject an SMS PDU into the android application framework.
*
* <p>Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier
@@ -653,140 +547,6 @@
}
/**
- * Send a multi-part text based SMS with messaging options. The callee should have already
- * divided the message into correctly sized parts by calling
- * <code>divideMessage</code>.
- *
- * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
- * {@link android.Manifest.permission#SEND_SMS} permission.</p>
- *
- * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
- * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
- * writes messages sent using this method to the SMS Provider (the default SMS app is always
- * responsible for writing its sent messages to the SMS Provider). For information about
- * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
- *
- * @param destinationAddress the address to send the message to
- * @param scAddress is the service center address or null to use
- * the current default SMSC
- * @param parts an <code>ArrayList</code> of strings that, in order,
- * comprise the original message
- * @param sentIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been sent.
- * The result code will be <code>Activity.RESULT_OK</code> for success,
- * or one of these errors:<br>
- * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
- * <code>RESULT_ERROR_RADIO_OFF</code><br>
- * <code>RESULT_ERROR_NULL_PDU</code><br>
- * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
- * the extra "errorCode" containing a radio technology specific value,
- * generally only useful for troubleshooting.<br>
- * The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applications,
- * which cause smaller number of SMS to be sent in checking period.
- * @param deliveryIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been delivered
- * to the recipient. The raw pdu of the status report is in the
- * extended data ("pdu").
- * @param priority Priority level of the message
- * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
- * ---------------------------------
- * PRIORITY | Level of Priority
- * ---------------------------------
- * '00' | Normal
- * '01' | Interactive
- * '10' | Urgent
- * '11' | Emergency
- * ----------------------------------
- * Any Other values included Negative considered as Invalid Priority Indicator of the message.
- * @param expectMore is a boolean to indicate the sending messages through same link or not.
- * @param validityPeriod Validity Period of the message in mins.
- * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
- * Validity Period(Minimum) -> 5 mins
- * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
- * Any Other values included Negative considered as Invalid Validity Period of the message.
- *
- * @throws IllegalArgumentException if destinationAddress or data are empty
- * {@hide}
- */
- public void sendMultipartTextMessage(
- String destinationAddress, String scAddress, ArrayList<String> parts,
- ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents,
- int priority, boolean expectMore, int validityPeriod) {
- sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, true /* persistMessage*/);
- }
-
- private void sendMultipartTextMessageInternal(
- String destinationAddress, String scAddress, List<String> parts,
- List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
- boolean persistMessage, int priority, boolean expectMore, int validityPeriod) {
- if (TextUtils.isEmpty(destinationAddress)) {
- throw new IllegalArgumentException("Invalid destinationAddress");
- }
- if (parts == null || parts.size() < 1) {
- throw new IllegalArgumentException("Invalid message body");
- }
-
- if (priority < 0x00 || priority > 0x03) {
- throw new IllegalArgumentException("Invalid priority");
- }
-
- if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) {
- throw new IllegalArgumentException("Invalid validity period");
- }
-
- if (parts.size() > 1) {
- try {
- ISms iccISms = getISmsServiceOrThrow();
- if (iccISms != null) {
- iccISms.sendMultipartTextForSubscriberWithOptions(getSubscriptionId(),
- ActivityThread.currentPackageName(), destinationAddress, scAddress,
- parts, sentIntents, deliveryIntents, persistMessage, priority,
- expectMore, validityPeriod);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- } else {
- PendingIntent sentIntent = null;
- PendingIntent deliveryIntent = null;
- if (sentIntents != null && sentIntents.size() > 0) {
- sentIntent = sentIntents.get(0);
- }
- if (deliveryIntents != null && deliveryIntents.size() > 0) {
- deliveryIntent = deliveryIntents.get(0);
- }
- sendTextMessageInternal(destinationAddress, scAddress, parts.get(0),
- sentIntent, deliveryIntent, persistMessage, priority, expectMore,
- validityPeriod);
- }
- }
-
- /**
- * Send a multi-part text based SMS without writing it into the SMS Provider.
- *
- * <p>Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
- * privileges.
- * </p>
- *
- * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList,
- * ArrayList, int, boolean, int)
- * @hide
- **/
- public void sendMultipartTextMessageWithoutPersisting(
- String destinationAddress, String scAddress, List<String> parts,
- List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
- int priority, boolean expectMore, int validityPeriod) {
- sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, false /* persistMessage*/, priority, expectMore,
- validityPeriod);
- }
-
- /**
* Send a data based SMS to a specific application port.
*
* <p class="note"><strong>Note:</strong> Using this method requires that your app has the
@@ -1249,7 +1009,7 @@
* <code>getAllMessagesFromIcc</code>
* @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
*/
- private ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
+ private static ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
if (records != null) {
int count = records.size();
@@ -1257,8 +1017,7 @@
SmsRawData data = records.get(i);
// List contains all records, including "free" records (null)
if (data != null) {
- SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes(),
- getSubscriptionId());
+ SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes());
if (sms != null) {
messages.add(sms);
}
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index a5d67c6..710eff0 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -83,7 +83,10 @@
public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153;
/** @hide */
- @StringDef({FORMAT_3GPP, FORMAT_3GPP2})
+ @StringDef(prefix = { "FORMAT_" }, value = {
+ FORMAT_3GPP,
+ FORMAT_3GPP2
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Format {}
@@ -271,31 +274,6 @@
}
/**
- * Create an SmsMessage from an SMS EF record.
- *
- * @param index Index of SMS record. This should be index in ArrayList
- * returned by SmsManager.getAllMessagesFromSim + 1.
- * @param data Record data.
- * @param subId Subscription Id of the SMS
- * @return An SmsMessage representing the record.
- *
- * @hide
- */
- public static SmsMessage createFromEfRecord(int index, byte[] data, int subId) {
- SmsMessageBase wrappedMessage;
-
- if (isCdmaVoice(subId)) {
- wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord(
- index, data);
- } else {
- wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord(
- index, data);
- }
-
- return wrappedMessage != null ? new SmsMessage(wrappedMessage) : null;
- }
-
- /**
* Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the
* length in bytes (not hex chars) less the SMSC header
*
@@ -847,7 +825,6 @@
int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(subId);
return (PHONE_TYPE_CDMA == activePhone);
}
-
/**
* Decide if the carrier supports long SMS.
* {@hide}
diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java
index d7b6142..942ea00 100644
--- a/telephony/java/android/telephony/Telephony.java
+++ b/telephony/java/android/telephony/Telephony.java
@@ -3342,6 +3342,12 @@
public static final String APN = "apn";
/**
+ * Prefix of Integrated Circuit Card Identifier.
+ * <P>Type: TEXT </P>
+ */
+ public static final String ICCID_PREFIX = "iccid_prefix";
+
+ /**
* User facing carrier name.
* <P>Type: TEXT </P>
*/
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 81806e5..28ae10b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -29,7 +29,6 @@
import android.annotation.WorkerThread;
import android.app.ActivityThread;
import android.app.PendingIntent;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
@@ -43,7 +42,6 @@
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.SystemProperties;
-import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.service.carrier.CarrierIdentifier;
import android.telecom.PhoneAccount;
@@ -979,6 +977,63 @@
*/
public static final int CDMA_ROAMING_MODE_ANY = 2;
+ /**
+ * An unknown carrier id. It could either be subscription unavailable or the subscription
+ * carrier cannot be recognized. Unrecognized carriers here means
+ * {@link #getSimOperator() MCC+MNC} cannot be identified.
+ */
+ public static final int UNKNOWN_CARRIER_ID = -1;
+
+ /**
+ * Broadcast Action: The subscription carrier identity has changed.
+ * This intent could be sent on the following events:
+ * <ul>
+ * <li>Subscription absent. Carrier identity could change from a valid id to
+ * {@link TelephonyManager#UNKNOWN_CARRIER_ID}.</li>
+ * <li>Subscription loaded. Carrier identity could change from
+ * {@link TelephonyManager#UNKNOWN_CARRIER_ID} to a valid id.</li>
+ * <li>The subscription carrier is recognized after a remote update.</li>
+ * </ul>
+ * The intent will have the following extra values:
+ * <ul>
+ * <li>{@link #EXTRA_CARRIER_ID} The up-to-date carrier id of the current subscription id.
+ * </li>
+ * <li>{@link #EXTRA_CARRIER_NAME} The up-to-date carrier name of the current subscription.
+ * </li>
+ * <li>{@link #EXTRA_SUBSCRIPTION_ID} The subscription id associated with the changed carrier
+ * identity.
+ * </li>
+ * </ul>
+ * <p class="note">This is a protected intent that can only be sent by the system.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED =
+ "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED";
+
+ /**
+ * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which indicates
+ * the updated carrier id {@link TelephonyManager#getSubscriptionCarrierId()} of the current
+ * subscription.
+ * <p>Will be {@link TelephonyManager#UNKNOWN_CARRIER_ID} if the subscription is unavailable or
+ * the carrier cannot be identified.
+ */
+ public static final String EXTRA_CARRIER_ID = "android.telephony.extra.CARRIER_ID";
+
+ /**
+ * An string extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which
+ * indicates the updated carrier name of the current subscription.
+ * {@see TelephonyManager#getSubscriptionCarrierName()}
+ * <p>Carrier name is a user-facing name of the carrier id {@link #EXTRA_CARRIER_ID},
+ * usually the brand name of the subsidiary (e.g. T-Mobile).
+ */
+ public static final String EXTRA_CARRIER_NAME = "android.telephony.extra.CARRIER_NAME";
+
+ /**
+ * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} to indicate the
+ * subscription which has changed.
+ */
+ public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID";
+
//
//
// Device Info
@@ -6509,6 +6564,9 @@
* @param uri The URI for the ringtone to play when receiving a voicemail from a specific
* PhoneAccount.
* @see #hasCarrierPrivileges
+ *
+ * @deprecated Use {@link android.provider.Settings#ACTION_CHANNEL_NOTIFICATION_SETTINGS}
+ * instead.
*/
public void setVoicemailRingtoneUri(PhoneAccountHandle phoneAccountHandle, Uri uri) {
try {
@@ -6551,6 +6609,9 @@
* @param enabled Whether to enable or disable vibration for voicemail notifications from a
* specific PhoneAccount.
* @see #hasCarrierPrivileges
+ *
+ * @deprecated Use {@link android.provider.Settings#ACTION_CHANNEL_NOTIFICATION_SETTINGS}
+ * instead.
*/
public void setVoicemailVibrationEnabled(PhoneAccountHandle phoneAccountHandle,
boolean enabled) {
@@ -6566,6 +6627,55 @@
}
/**
+ * Returns carrier id of the current subscription.
+ * <p>To recognize a carrier (including MVNO) as a first class identity, assign each carrier
+ * with a canonical integer a.k.a carrier id.
+ *
+ * @return Carrier id of the current subscription. Return {@link #UNKNOWN_CARRIER_ID} if the
+ * subscription is unavailable or the carrier cannot be identified.
+ * @throws IllegalStateException if telephony service is unavailable.
+ */
+ public int getSubscriptionCarrierId() {
+ try {
+ ITelephony service = getITelephony();
+ return service.getSubscriptionCarrierId(getSubId());
+ } catch (RemoteException ex) {
+ // This could happen if binder process crashes.
+ ex.rethrowAsRuntimeException();
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing.
+ throw new IllegalStateException("Telephony service unavailable");
+ }
+ return UNKNOWN_CARRIER_ID;
+ }
+
+ /**
+ * Returns carrier name of the current subscription.
+ * <p>Carrier name is a user-facing name of carrier id {@link #getSubscriptionCarrierId()},
+ * usually the brand name of the subsidiary (e.g. T-Mobile). Each carrier could configure
+ * multiple {@link #getSimOperatorName() SPN} but should have a single carrier name.
+ * Carrier name is not a canonical identity, use {@link #getSubscriptionCarrierId()} instead.
+ * <p>The returned carrier name is unlocalized.
+ *
+ * @return Carrier name of the current subscription. Return {@code null} if the subscription is
+ * unavailable or the carrier cannot be identified.
+ * @throws IllegalStateException if telephony service is unavailable.
+ */
+ public String getSubscriptionCarrierName() {
+ try {
+ ITelephony service = getITelephony();
+ return service.getSubscriptionCarrierName(getSubId());
+ } catch (RemoteException ex) {
+ // This could happen if binder process crashes.
+ ex.rethrowAsRuntimeException();
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing.
+ throw new IllegalStateException("Telephony service unavailable");
+ }
+ return null;
+ }
+
+ /**
* Return the application ID for the app type like {@link APPTYPE_CSIM}.
*
* Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission
@@ -6641,6 +6751,7 @@
* @return PRLVersion or null if error.
* @hide
*/
+ @SystemApi
public String getCdmaPrlVersion() {
return getCdmaPrlVersion(getSubId());
}
@@ -6866,6 +6977,8 @@
* @return true if phone is in emergency callback mode
* @hide
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean getEmergencyCallbackMode() {
return getEmergencyCallbackMode(getSubId());
}
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/telephony/java/android/telephony/data/DataCallResponse.aidl
similarity index 71%
rename from telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
rename 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..da51c86
--- /dev/null
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -0,0 +1,267 @@
+/*
+ * 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(" addresses=").append(mAddresses)
+ .append(" dnses=").append(mDnses)
+ .append(" gateways=").append(mGateways)
+ .append(" pcscf=").append(mPcscfs)
+ .append(" mtu=").append(mMtu)
+ .append("}");
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals (Object o) {
+ if (this == o) return true;
+
+ if (o == null || !(o instanceof DataCallResponse)) {
+ return false;
+ }
+
+ DataCallResponse other = (DataCallResponse) o;
+ return this.mStatus == other.mStatus
+ && this.mSuggestedRetryTime == other.mSuggestedRetryTime
+ && this.mCid == other.mCid
+ && this.mActive == other.mActive
+ && this.mType.equals(other.mType)
+ && this.mIfname.equals(other.mIfname)
+ && mAddresses.size() == other.mAddresses.size()
+ && mAddresses.containsAll(other.mAddresses)
+ && mDnses.size() == other.mDnses.size()
+ && mDnses.containsAll(other.mDnses)
+ && mGateways.size() == other.mGateways.size()
+ && mGateways.containsAll(other.mGateways)
+ && mPcscfs.size() == other.mPcscfs.size()
+ && mPcscfs.containsAll(other.mPcscfs)
+ && mMtu == other.mMtu;
+ }
+
+ @Override
+ public int hashCode() {
+ return mStatus * 31
+ + mSuggestedRetryTime * 37
+ + mCid * 41
+ + mActive * 43
+ + mType.hashCode() * 47
+ + mIfname.hashCode() * 53
+ + mAddresses.hashCode() * 59
+ + mDnses.hashCode() * 61
+ + mGateways.hashCode() * 67
+ + mPcscfs.hashCode() * 71
+ + mMtu * 73;
+ }
+
+ @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..00d212a
--- /dev/null
+++ b/telephony/java/android/telephony/data/InterfaceAddress.java
@@ -0,0 +1,127 @@
+/*
+ * 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 boolean equals (Object o) {
+ if (this == o) return true;
+
+ if (o == null || !(o instanceof InterfaceAddress)) {
+ return false;
+ }
+
+ InterfaceAddress other = (InterfaceAddress) o;
+ return this.mInetAddress.equals(other.mInetAddress)
+ && this.mPrefixLength == other.mPrefixLength;
+ }
+
+ @Override
+ public int hashCode() {
+ return mInetAddress.hashCode() * 31 + mPrefixLength * 37;
+ }
+
+ @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/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index 5a4db99..1670e6b 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -16,15 +16,23 @@
package android.telephony.ims.stub;
+import android.content.Context;
+import android.content.Intent;
import android.os.RemoteException;
+import android.util.Log;
import com.android.ims.ImsConfig;
import com.android.ims.ImsConfigListener;
import com.android.ims.internal.IImsConfig;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+
/**
- * Base implementation of ImsConfig, which implements stub versions of the methods
- * in the IImsConfig AIDL. Override the methods that your implementation of ImsConfig supports.
+ * Base implementation of ImsConfig.
+ * Override the methods that your implementation of ImsConfig supports.
*
* DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
* will break other implementations of ImsConfig maintained by other ImsServices.
@@ -34,10 +42,25 @@
* 1) Items provisioned by the operator.
* 2) Items configured by user. Mainly service feature class.
*
+ * The inner class {@link ImsConfigStub} implements methods of IImsConfig AIDL interface.
+ * The IImsConfig AIDL interface is called by ImsConfig, which may exist in many other processes.
+ * ImsConfigImpl access to the configuration parameters may be arbitrarily slow, especially in
+ * during initialization, or times when a lot of configuration parameters are being set/get
+ * (such as during boot up or SIM card change). By providing a cache in ImsConfigStub, we can speed
+ * up access to these configuration parameters, so a query to the ImsConfigImpl does not have to be
+ * performed every time.
* @hide
*/
-public class ImsConfigImplBase extends IImsConfig.Stub {
+public class ImsConfigImplBase {
+
+ static final private String TAG = "ImsConfigImplBase";
+
+ ImsConfigStub mImsConfigStub;
+
+ public ImsConfigImplBase(Context context) {
+ mImsConfigStub = new ImsConfigStub(this, context);
+ }
/**
* Gets the value for ims service/capabilities parameters from the provisioned
@@ -46,7 +69,6 @@
* @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
* @return value in Integer format.
*/
- @Override
public int getProvisionedValue(int item) throws RemoteException {
return -1;
}
@@ -58,7 +80,6 @@
* @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
* @return value in String format.
*/
- @Override
public String getProvisionedStringValue(int item) throws RemoteException {
return null;
}
@@ -72,7 +93,6 @@
* @param value in Integer format.
* @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
*/
- @Override
public int setProvisionedValue(int item, int value) throws RemoteException {
return ImsConfig.OperationStatusConstants.FAILED;
}
@@ -86,7 +106,6 @@
* @param value in String format.
* @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
*/
- @Override
public int setProvisionedStringValue(int item, String value) throws RemoteException {
return ImsConfig.OperationStatusConstants.FAILED;
}
@@ -100,7 +119,6 @@
* @param network as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
* @param listener feature value returned asynchronously through listener.
*/
- @Override
public void getFeatureValue(int feature, int network, ImsConfigListener listener)
throws RemoteException {
}
@@ -115,7 +133,6 @@
* @param value as defined in com.android.ims.ImsConfig#FeatureValueConstants.
* @param listener, provided if caller needs to be notified for set result.
*/
- @Override
public void setFeatureValue(int feature, int network, int value, ImsConfigListener listener)
throws RemoteException {
}
@@ -124,7 +141,6 @@
* Gets the value for IMS VoLTE provisioned.
* This should be the same as the operator provisioned value if applies.
*/
- @Override
public boolean getVolteProvisioned() throws RemoteException {
return false;
}
@@ -134,7 +150,6 @@
*
* @param listener Video quality value returned asynchronously through listener.
*/
- @Override
public void getVideoQuality(ImsConfigListener listener) throws RemoteException {
}
@@ -144,7 +159,233 @@
* @param quality, defines the value of video quality.
* @param listener, provided if caller needs to be notified for set result.
*/
- @Override
public void setVideoQuality(int quality, ImsConfigListener listener) throws RemoteException {
}
+
+ public IImsConfig getIImsConfig() { return mImsConfigStub; }
+
+ /**
+ * Updates provisioning value and notifies the framework of the change.
+ * Doesn't call #setProvisionedValue and assumes the result succeeded.
+ * This should only be used by modem when they implicitly changed provisioned values.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in Integer format.
+ */
+ public final void notifyProvisionedValueChanged(int item, int value) {
+ mImsConfigStub.updateCachedValue(item, value, true);
+ }
+
+ /**
+ * Updates provisioning value and notifies the framework of the change.
+ * Doesn't call #setProvisionedValue and assumes the result succeeded.
+ * This should only be used by modem when they implicitly changed provisioned values.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in String format.
+ */
+ public final void notifyProvisionedValueChanged(int item, String value) {
+ mImsConfigStub.updateCachedValue(item, value, true);
+ }
+
+ /**
+ * Implements the IImsConfig AIDL interface, which is called by potentially many processes
+ * in order to get/set configuration parameters.
+ *
+ * It holds an object of ImsConfigImplBase class which is usually extended by ImsConfigImpl
+ * with actual implementations from vendors. This class caches provisioned values from
+ * ImsConfigImpl layer because queries through ImsConfigImpl can be slow. When query goes in,
+ * it first checks cache layer. If missed, it will call the vendor implementation of
+ * ImsConfigImplBase API.
+ * and cache the return value if the set succeeds.
+ *
+ * Provides APIs to get/set the IMS service feature/capability/parameters.
+ * The config items include:
+ * 1) Items provisioned by the operator.
+ * 2) Items configured by user. Mainly service feature class.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ static public class ImsConfigStub extends IImsConfig.Stub {
+ Context mContext;
+ WeakReference<ImsConfigImplBase> mImsConfigImplBaseWeakReference;
+ private HashMap<Integer, Integer> mProvisionedIntValue = new HashMap<>();
+ private HashMap<Integer, String> mProvisionedStringValue = new HashMap<>();
+
+ @VisibleForTesting
+ public ImsConfigStub(ImsConfigImplBase imsConfigImplBase, Context context) {
+ mContext = context;
+ mImsConfigImplBaseWeakReference =
+ new WeakReference<ImsConfigImplBase>(imsConfigImplBase);
+ }
+
+ /**
+ * Gets the value for ims service/capabilities parameters. It first checks its local cache,
+ * if missed, it will call ImsConfigImplBase.getProvisionedValue.
+ * Synchronous blocking call.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @return value in Integer format.
+ */
+ @Override
+ public synchronized int getProvisionedValue(int item) throws RemoteException {
+ if (mProvisionedIntValue.containsKey(item)) {
+ return mProvisionedIntValue.get(item);
+ } else {
+ int retVal = getImsConfigImpl().getProvisionedValue(item);
+ if (retVal != ImsConfig.OperationStatusConstants.UNKNOWN) {
+ updateCachedValue(item, retVal, false);
+ }
+ return retVal;
+ }
+ }
+
+ /**
+ * Gets the value for ims service/capabilities parameters. It first checks its local cache,
+ * if missed, it will call #ImsConfigImplBase.getProvisionedValue.
+ * Synchronous blocking call.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @return value in String format.
+ */
+ @Override
+ public synchronized String getProvisionedStringValue(int item) throws RemoteException {
+ if (mProvisionedIntValue.containsKey(item)) {
+ return mProvisionedStringValue.get(item);
+ } else {
+ String retVal = getImsConfigImpl().getProvisionedStringValue(item);
+ if (retVal != null) {
+ updateCachedValue(item, retVal, false);
+ }
+ return retVal;
+ }
+ }
+
+ /**
+ * Sets the value for IMS service/capabilities parameters by the operator device
+ * management entity. It sets the config item value in the provisioned storage
+ * from which the master value is derived, and write it into local cache.
+ * Synchronous blocking call.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in Integer format.
+ * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+ */
+ @Override
+ public synchronized int setProvisionedValue(int item, int value) throws RemoteException {
+ mProvisionedIntValue.remove(item);
+ int retVal = getImsConfigImpl().setProvisionedValue(item, value);
+ if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
+ updateCachedValue(item, retVal, true);
+ } else {
+ Log.d(TAG, "Set provision value of " + item +
+ " to " + value + " failed with error code " + retVal);
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Sets the value for IMS service/capabilities parameters by the operator device
+ * management entity. It sets the config item value in the provisioned storage
+ * from which the master value is derived, and write it into local cache.
+ * Synchronous blocking call.
+ *
+ * @param item as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in String format.
+ * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+ */
+ @Override
+ public synchronized int setProvisionedStringValue(int item, String value)
+ throws RemoteException {
+ mProvisionedStringValue.remove(item);
+ int retVal = getImsConfigImpl().setProvisionedStringValue(item, value);
+ if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
+ updateCachedValue(item, retVal, true);
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Wrapper function to call ImsConfigImplBase.getFeatureValue.
+ */
+ @Override
+ public void getFeatureValue(int feature, int network, ImsConfigListener listener)
+ throws RemoteException {
+ getImsConfigImpl().getFeatureValue(feature, network, listener);
+ }
+
+ /**
+ * Wrapper function to call ImsConfigImplBase.setFeatureValue.
+ */
+ @Override
+ public void setFeatureValue(int feature, int network, int value, ImsConfigListener listener)
+ throws RemoteException {
+ getImsConfigImpl().setFeatureValue(feature, network, value, listener);
+ }
+
+ /**
+ * Wrapper function to call ImsConfigImplBase.getVolteProvisioned.
+ */
+ @Override
+ public boolean getVolteProvisioned() throws RemoteException {
+ return getImsConfigImpl().getVolteProvisioned();
+ }
+
+ /**
+ * Wrapper function to call ImsConfigImplBase.getVideoQuality.
+ */
+ @Override
+ public void getVideoQuality(ImsConfigListener listener) throws RemoteException {
+ getImsConfigImpl().getVideoQuality(listener);
+ }
+
+ /**
+ * Wrapper function to call ImsConfigImplBase.setVideoQuality.
+ */
+ @Override
+ public void setVideoQuality(int quality, ImsConfigListener listener)
+ throws RemoteException {
+ getImsConfigImpl().setVideoQuality(quality, listener);
+ }
+
+ private ImsConfigImplBase getImsConfigImpl() throws RemoteException {
+ ImsConfigImplBase ref = mImsConfigImplBaseWeakReference.get();
+ if (ref == null) {
+ throw new RemoteException("Fail to get ImsConfigImpl");
+ } else {
+ return ref;
+ }
+ }
+
+ private void sendImsConfigChangedIntent(int item, int value) {
+ sendImsConfigChangedIntent(item, Integer.toString(value));
+ }
+
+ private void sendImsConfigChangedIntent(int item, String value) {
+ Intent configChangedIntent = new Intent(ImsConfig.ACTION_IMS_CONFIG_CHANGED);
+ configChangedIntent.putExtra(ImsConfig.EXTRA_CHANGED_ITEM, item);
+ configChangedIntent.putExtra(ImsConfig.EXTRA_NEW_VALUE, value);
+ if (mContext != null) {
+ mContext.sendBroadcast(configChangedIntent);
+ }
+ }
+
+ protected synchronized void updateCachedValue(int item, int value, boolean notifyChange) {
+ mProvisionedIntValue.put(item, value);
+ if (notifyChange) {
+ sendImsConfigChangedIntent(item, value);
+ }
+ }
+
+ protected synchronized void updateCachedValue(
+ int item, String value, boolean notifyChange) {
+ mProvisionedStringValue.put(item, value);
+ if (notifyChange) {
+ sendImsConfigChangedIntent(item, value);
+ }
+ }
+ }
}
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/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index cf4c47b..cd0c4b1 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -619,6 +619,7 @@
Rlog.d(TAG, "setProvisionedValue(): item = " + item +
" value = " + value + " ret = " + ret);
}
+
return ret;
}
@@ -647,6 +648,7 @@
Rlog.d(TAG, "setProvisionedStringValue(): item = " + item +
", value =" + value);
}
+
return ret;
}
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/services/core/java/com/android/server/timezone/ClockHelper.java b/telephony/java/com/android/ims/internal/ISmsListener.aidl
similarity index 62%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to telephony/java/com/android/ims/internal/ISmsListener.aidl
index 353728a..1266f04 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/telephony/java/com/android/ims/internal/ISmsListener.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 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,12 +14,14 @@
* limitations under the License.
*/
-package com.android.server.timezone;
+package com.android.ims.internal;
/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
+ * See SmsFeature for more information.
+ * {@hide}
*/
-interface ClockHelper {
-
- long currentTimestamp();
-}
+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/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index a4eb424..fe37531 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -187,57 +187,6 @@
in PendingIntent deliveryIntent, in boolean persistMessage);
/**
- * Send an SMS with options using Subscription Id.
- *
- * @param subId the subId on which the SMS has to be sent.
- * @param destAddr the address to send the message to
- * @param scAddr the SMSC to send the message through, or NULL for the
- * default SMSC
- * @param text the body of the message to send
- * @param sentIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is sucessfully sent, or failed.
- * The result code will be <code>Activity.RESULT_OK<code> for success,
- * or one of these errors:<br>
- * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
- * <code>RESULT_ERROR_RADIO_OFF</code><br>
- * <code>RESULT_ERROR_NULL_PDU</code><br>
- * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
- * the extra "errorCode" containing a radio technology specific value,
- * generally only useful for troubleshooting.<br>
- * The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applications,
- * which cause smaller number of SMS to be sent in checking period.
- * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is delivered to the recipient. The
- * raw pdu of the status report is in the extended data ("pdu").
- * @param persistMessageForNonDefaultSmsApp whether the sent message should
- * be automatically persisted in the SMS db. It only affects messages sent
- * by a non-default SMS app. Currently only the carrier app can set this
- * parameter to false to skip auto message persistence.
- * @param priority Priority level of the message
- * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
- * ---------------------------------
- * PRIORITY | Level of Priority
- * ---------------------------------
- * '00' | Normal
- * '01' | Interactive
- * '10' | Urgent
- * '11' | Emergency
- * ----------------------------------
- * Any Other values included Negative considered as Invalid Priority Indicator of the message.
- * @param expectMore is a boolean to indicate the sending message is multi segmented or not.
- * @param validityPeriod Validity Period of the message in mins.
- * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
- * Validity Period(Minimum) -> 5 mins
- * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
- * Any Other values included Negative considered as Invalid Validity Period of the message.
- */
- void sendTextForSubscriberWithOptions(in int subId, String callingPkg, in String destAddr,
- in String scAddr, in String text, in PendingIntent sentIntent,
- in PendingIntent deliveryIntent, in boolean persistMessageForNonDefaultSmsApp,
- in int priority, in boolean expectMore, in int validityPeriod);
-
- /**
* Inject an SMS PDU into the android platform.
*
* @param subId the subId on which the SMS has to be injected.
@@ -285,56 +234,6 @@
in List<PendingIntent> deliveryIntents, in boolean persistMessageForNonDefaultSmsApp);
/**
- * Send a multi-part text based SMS with options using Subscription Id.
- *
- * @param subId the subId on which the SMS has to be sent.
- * @param destinationAddress the address to send the message to
- * @param scAddress is the service center address or null to use
- * the current default SMSC
- * @param parts an <code>ArrayList</code> of strings that, in order,
- * comprise the original message
- * @param sentIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been sent.
- * The result code will be <code>Activity.RESULT_OK<code> for success,
- * or one of these errors:
- * <code>RESULT_ERROR_GENERIC_FAILURE</code>
- * <code>RESULT_ERROR_RADIO_OFF</code>
- * <code>RESULT_ERROR_NULL_PDU</code>.
- * @param deliveryIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been delivered
- * to the recipient. The raw pdu of the status report is in the
- * extended data ("pdu").
- * @param persistMessageForNonDefaultSmsApp whether the sent message should
- * be automatically persisted in the SMS db. It only affects messages sent
- * by a non-default SMS app. Currently only the carrier app can set this
- * parameter to false to skip auto message persistence.
- * @param priority Priority level of the message
- * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
- * ---------------------------------
- * PRIORITY | Level of Priority
- * ---------------------------------
- * '00' | Normal
- * '01' | Interactive
- * '10' | Urgent
- * '11' | Emergency
- * ----------------------------------
- * Any Other values included Negative considered as Invalid Priority Indicator of the message.
- * @param expectMore is a boolean to indicate the sending message is multi segmented or not.
- * @param validityPeriod Validity Period of the message in mins.
- * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
- * Validity Period(Minimum) -> 5 mins
- * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
- * Any Other values included Negative considered as Invalid Validity Period of the message.
- */
- void sendMultipartTextForSubscriberWithOptions(in int subId, String callingPkg,
- in String destinationAddress, in String scAddress, in List<String> parts,
- in List<PendingIntent> sentIntents, in List<PendingIntent> deliveryIntents,
- in boolean persistMessageForNonDefaultSmsApp, in int priority, in boolean expectMore,
- in int validityPeriod);
-
- /**
* Enable reception of cell broadcast (SMS-CB) messages with the given
* message identifier and RAN type. The RAN type specify this message ID
* belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients
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/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index fd6091a..a9f8f45 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1298,6 +1298,34 @@
*/
List<CarrierIdentifier> getAllowedCarriers(int slotIndex);
+ /**
+ * Returns carrier id of the given subscription.
+ * <p>To recognize carrier as a first class identity, assign each carrier with a canonical
+ * integer a.k.a carrier id.
+ *
+ * @param subId The subscription id
+ * @return Carrier id of given subscription id. return {@link #UNKNOWN_CARRIER_ID} if
+ * subscription is unavailable or carrier cannot be identified.
+ * @throws IllegalStateException if telephony service is unavailable.
+ * @hide
+ */
+ int getSubscriptionCarrierId(int subId);
+
+ /**
+ * Returns carrier name of the given subscription.
+ * <p>Carrier name is a user-facing name of carrier id {@link #getSubscriptionCarrierId(int)},
+ * usually the brand name of the subsidiary (e.g. T-Mobile). Each carrier could configure
+ * multiple {@link #getSimOperatorName() SPN} but should have a single carrier name.
+ * Carrier name is not canonical identity, use {@link #getSubscriptionCarrierId(int)} instead.
+ * <p>Returned carrier name is unlocalized.
+ *
+ * @return Carrier name of given subscription id. return {@code null} if subscription is
+ * unavailable or carrier cannot be identified.
+ * @throws IllegalStateException if telephony service is unavailable.
+ * @hide
+ */
+ String getSubscriptionCarrierName(int subId);
+
/**
* Action set from carrier signalling broadcast receivers to enable/disable metered apns
* Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
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/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 14c5f4b..7a53ef6 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -99,15 +99,6 @@
private static final int RETURN_NO_ACK = 0;
private static final int RETURN_ACK = 1;
- /**
- * Supported priority modes for CDMA SMS messages
- * (See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1)
- */
- private static final int PRIORITY_NORMAL = 0x0;
- private static final int PRIORITY_INTERACTIVE = 0x1;
- private static final int PRIORITY_URGENT = 0x2;
- private static final int PRIORITY_EMERGENCY = 0x3;
-
private SmsEnvelope mEnvelope;
private BearerData mBearerData;
@@ -220,26 +211,6 @@
*/
public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, String message,
boolean statusReportRequested, SmsHeader smsHeader) {
- return getSubmitPdu(scAddr, destAddr, message, statusReportRequested, smsHeader, -1);
- }
-
- /**
- * Get an SMS-SUBMIT PDU for a destination address and a message
- *
- * @param scAddr Service Centre address. Null means use default.
- * @param destAddr Address of the recipient.
- * @param message String representation of the message payload.
- * @param statusReportRequested Indicates whether a report is requested for this message.
- * @param smsHeader Array containing the data for the User Data Header, preceded
- * by the Element Identifiers.
- * @param priority Priority level of the message
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
- * @hide
- */
- public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, String message,
- boolean statusReportRequested, SmsHeader smsHeader, int priority) {
/**
* TODO(cleanup): Do we really want silent failure like this?
@@ -253,7 +224,7 @@
UserData uData = new UserData();
uData.payloadStr = message;
uData.userDataHeader = smsHeader;
- return privateGetSubmitPdu(destAddr, statusReportRequested, uData, priority);
+ return privateGetSubmitPdu(destAddr, statusReportRequested, uData);
}
/**
@@ -311,22 +282,6 @@
}
/**
- * Get an SMS-SUBMIT PDU for a data message to a destination address & port
- *
- * @param destAddr the address of the destination for the message
- * @param userData the data for the message
- * @param statusReportRequested Indicates whether a report is requested for this message.
- * @param priority Priority level of the message
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
- */
- public static SubmitPdu getSubmitPdu(String destAddr, UserData userData,
- boolean statusReportRequested, int priority) {
- return privateGetSubmitPdu(destAddr, statusReportRequested, userData, priority);
- }
-
- /**
* Note: This function is a GSM specific functionality which is not supported in CDMA mode.
*/
@Override
@@ -809,15 +764,6 @@
*/
private static SubmitPdu privateGetSubmitPdu(String destAddrStr, boolean statusReportRequested,
UserData userData) {
- return privateGetSubmitPdu(destAddrStr, statusReportRequested, userData, -1);
- }
-
- /**
- * Creates BearerData and Envelope from parameters for a Submit SMS.
- * @return byte stream for SubmitPdu.
- */
- private static SubmitPdu privateGetSubmitPdu(String destAddrStr, boolean statusReportRequested,
- UserData userData, int priority) {
/**
* TODO(cleanup): give this function a more meaningful name.
@@ -846,10 +792,6 @@
bearerData.userAckReq = false;
bearerData.readAckReq = false;
bearerData.reportReq = false;
- if (priority >= PRIORITY_NORMAL && priority <= PRIORITY_EMERGENCY) {
- bearerData.priorityIndicatorSet = true;
- bearerData.priority = priority;
- }
bearerData.userData = userData;
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 4f5bfa9..1ca19e0 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -89,18 +89,6 @@
private int mVoiceMailCount = 0;
- private static final int VALIDITY_PERIOD_FORMAT_NONE = 0x00;
- private static final int VALIDITY_PERIOD_FORMAT_ENHANCED = 0x01;
- private static final int VALIDITY_PERIOD_FORMAT_RELATIVE = 0x02;
- private static final int VALIDITY_PERIOD_FORMAT_ABSOLUTE = 0x03;
-
- //Validity Period min - 5 mins
- private static final int VALIDITY_PERIOD_MIN = 5;
- //Validity Period max - 63 weeks
- private static final int VALIDITY_PERIOD_MAX = 635040;
-
- private static final int INVALID_VALIDITY_PERIOD = -1;
-
public static class SubmitPdu extends SubmitPduBase {
}
@@ -214,45 +202,6 @@
}
/**
- * Get Encoded Relative Validty Period Value from Validity period in mins.
- *
- * @param validityPeriod Validity period in mins.
- *
- * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
- * ||relValidityPeriod (TP-VP) || || validityPeriod ||
- *
- * 0 to 143 ---> (TP-VP + 1) x 5 minutes
- *
- * 144 to 167 ---> 12 hours + ((TP-VP -143) x 30 minutes)
- *
- * 168 to 196 ---> (TP-VP - 166) x 1 day
- *
- * 197 to 255 ---> (TP-VP - 192) x 1 week
- *
- * @return relValidityPeriod Encoded Relative Validity Period Value.
- * @hide
- */
- public static int getRelativeValidityPeriod(int validityPeriod) {
- int relValidityPeriod = INVALID_VALIDITY_PERIOD;
-
- if (validityPeriod < VALIDITY_PERIOD_MIN || validityPeriod > VALIDITY_PERIOD_MAX) {
- Rlog.e(LOG_TAG,"Invalid Validity Period" + validityPeriod);
- return relValidityPeriod;
- }
-
- if (validityPeriod <= 720) {
- relValidityPeriod = (validityPeriod / 5) - 1;
- } else if (validityPeriod <= 1440) {
- relValidityPeriod = ((validityPeriod - 720) / 30) + 143;
- } else if (validityPeriod <= 43200) {
- relValidityPeriod = (validityPeriod / 1440) + 166;
- } else if (validityPeriod <= 635040) {
- relValidityPeriod = (validityPeriod / 10080) + 192;
- }
- return relValidityPeriod;
- }
-
- /**
* Get an SMS-SUBMIT PDU for a destination address and a message
*
* @param scAddress Service Centre address. Null means use default.
@@ -287,29 +236,6 @@
String destinationAddress, String message,
boolean statusReportRequested, byte[] header, int encoding,
int languageTable, int languageShiftTable) {
- return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested,
- header, encoding, languageTable, languageShiftTable, -1);
- }
-
- /**
- * Get an SMS-SUBMIT PDU for a destination address and a message using the
- * specified encoding.
- *
- * @param scAddress Service Centre address. Null means use default.
- * @param encoding Encoding defined by constants in
- * com.android.internal.telephony.SmsConstants.ENCODING_*
- * @param languageTable
- * @param languageShiftTable
- * @param validityPeriod Validity Period of the message in Minutes.
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
- * @hide
- */
- public static SubmitPdu getSubmitPdu(String scAddress,
- String destinationAddress, String message,
- boolean statusReportRequested, byte[] header, int encoding,
- int languageTable, int languageShiftTable, int validityPeriod) {
// Perform null parameter checks.
if (message == null || destinationAddress == null) {
@@ -346,19 +272,8 @@
}
SubmitPdu ret = new SubmitPdu();
-
- int validityPeriodFormat = VALIDITY_PERIOD_FORMAT_NONE;
- int relativeValidityPeriod = INVALID_VALIDITY_PERIOD;
-
- // TP-Validity-Period-Format (TP-VPF) in 3GPP TS 23.040 V6.8.1 section 9.2.3.3
- //bit 4:3 = 10 - TP-VP field present - relative format
- if((relativeValidityPeriod = getRelativeValidityPeriod(validityPeriod)) >= 0) {
- validityPeriodFormat = VALIDITY_PERIOD_FORMAT_RELATIVE;
- }
-
- byte mtiByte = (byte)(0x01 | (validityPeriodFormat << 0x03) |
- (header != null ? 0x40 : 0x00));
-
+ // MTI = SMS-SUBMIT, UDHI = header != null
+ byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00));
ByteArrayOutputStream bo = getSubmitPduHead(
scAddress, destinationAddress, mtiByte,
statusReportRequested, ret);
@@ -423,11 +338,7 @@
bo.write(0x08);
}
- if (validityPeriodFormat == VALIDITY_PERIOD_FORMAT_RELATIVE) {
- // ( TP-Validity-Period - relative format)
- bo.write(relativeValidityPeriod);
- }
-
+ // (no TP-Validity-Period)
bo.write(userData, 0, userData.length);
ret.encodedMessage = bo.toByteArray();
return ret;
@@ -477,24 +388,6 @@
}
/**
- * Get an SMS-SUBMIT PDU for a destination address and a message
- *
- * @param scAddress Service Centre address. Null means use default.
- * @param destinationAddress the address of the destination for the message
- * @param statusReportRequested staus report of the message Requested
- * @param validityPeriod Validity Period of the message in Minutes.
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
- */
- public static SubmitPdu getSubmitPdu(String scAddress,
- String destinationAddress, String message,
- boolean statusReportRequested, int validityPeriod) {
- return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested,
- null, ENCODING_UNKNOWN, 0, 0, validityPeriod);
- }
-
- /**
* Get an SMS-SUBMIT PDU for a data message to a destination address & port
*
* @param scAddress Service Centre address. null == use default
diff --git a/test-base/Android.bp b/test-base/Android.bp
new file mode 100644
index 0000000..a3fd345
--- /dev/null
+++ b/test-base/Android.bp
@@ -0,0 +1,88 @@
+//
+// 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.
+//
+
+// 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.
+java_library {
+ name: "android.test.base",
+
+ srcs: ["src/**/*.java"],
+
+ no_framework_libs: true,
+ libs: [
+ "framework",
+ ],
+
+}
+
+// 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.
+java_library {
+ name: "legacy-test",
+ static_libs: ["android.test.base"],
+
+ no_framework_libs: true,
+ libs: [
+ "framework",
+ ],
+}
+
+// Build the repackaged.android.test.base library
+// ==============================================
+// This contains repackaged versions of the classes from legacy-test.
+java_library_static {
+ name: "repackaged.android.test.base",
+
+ static_libs: ["android.test.base"],
+
+ no_framework_libs: true,
+ libs: [
+ "framework",
+ ],
+
+ jarjar_rules: "jarjar-rules.txt",
+}
+
+// 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.
+java_library_static {
+ name: "legacy-android-test",
+
+ srcs: [
+ "src/android/**/*.java",
+ "src/com/**/*.java",
+ ],
+
+ static_libs: [
+ "android.test.runner",
+ "android.test.mock",
+ ],
+
+ no_framework_libs: true,
+ libs: [
+ "framework",
+ "junit",
+ ],
+}
diff --git a/test-base/Android.mk b/test-base/Android.mk
index 9fc70f3..5e5d040 100644
--- a/test-base/Android.mk
+++ b/test-base/Android.mk
@@ -16,63 +16,8 @@
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-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)
-
-# 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
# ==========================================================
@@ -165,23 +110,7 @@
@echo Copying removed.txt
$(hide) $(ACP) $(ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_BASE_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)
+endif # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
# Build the legacy.test.stubs library
# ===================================
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
new file mode 100644
index 0000000..8eddec4
--- /dev/null
+++ b/test-mock/Android.bp
@@ -0,0 +1,39 @@
+//
+// 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.
+//
+
+// Build the android.test.mock library
+// ===================================
+java_library {
+ name: "android.test.mock",
+
+ srcs: ["src/**/*.java"],
+
+ no_framework_libs: true,
+ libs: [
+ "framework",
+ "legacy-test",
+ ],
+}
+
+// Build the repackaged.android.test.mock library
+// ==============================================
+java_library_static {
+ name: "repackaged.android.test.mock",
+
+ static_libs: ["android.test.mock"],
+
+ jarjar_rules: "jarjar-rules.txt",
+}
diff --git a/test-mock/Android.mk b/test-mock/Android.mk
index e4af17c..a761a07 100644
--- a/test-mock/Android.mk
+++ b/test-mock/Android.mk
@@ -18,32 +18,6 @@
android_test_mock_source_files := $(call all-java-files-under, src/android/test/mock)
-# Build the repackaged.android.test.mock library
-# ==============================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework legacy-test
-
-LOCAL_JARJAR_RULES := $(LOCAL_PATH)/../test-base/jarjar-rules.txt
-
-LOCAL_MODULE:= repackaged.android.test.mock
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# Build the android.test.mock library
-# ===================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
-
-LOCAL_MODULE:= android.test.mock
-
-include $(BUILD_JAVA_LIBRARY)
-
# For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
diff --git a/test-mock/jarjar-rules.txt b/test-mock/jarjar-rules.txt
new file mode 120000
index 0000000..f6f7913
--- /dev/null
+++ b/test-mock/jarjar-rules.txt
@@ -0,0 +1 @@
+../test-base/jarjar-rules.txt
\ No newline at end of file
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 5e5ba46..4dfd050 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -19,13 +19,12 @@
import android.annotation.SystemApi;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
-import android.app.Notification;
+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.BroadcastReceiver;
import android.content.IntentSender;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
@@ -44,8 +43,8 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.UserHandle;
-import android.view.DisplayAdjustments;
import android.view.Display;
+import android.view.DisplayAdjustments;
import java.io.File;
import java.io.FileInputStream;
@@ -53,6 +52,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.concurrent.Executor;
/**
* A mock {@link android.content.Context} class. All methods are non-functional and throw
@@ -87,6 +87,11 @@
}
@Override
+ public Executor getMainExecutor() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public Context getApplicationContext() {
throw new UnsupportedOperationException();
}
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.bp b/test-runner/Android.bp
new file mode 100644
index 0000000..104ae82
--- /dev/null
+++ b/test-runner/Android.bp
@@ -0,0 +1,40 @@
+//
+// 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.
+//
+
+// Build the android.test.runner library
+// =====================================
+java_library {
+ name: "android.test.runner",
+
+ srcs: ["src/**/*.java"],
+
+ no_framework_libs: true,
+ libs: [
+ "framework",
+ "legacy-test",
+ "android.test.mock",
+ ],
+}
+
+// Build the repackaged.android.test.runner library
+// ================================================
+java_library_static {
+ name: "repackaged.android.test.runner",
+
+ static_libs: ["android.test.runner"],
+
+ jarjar_rules: "jarjar-rules.txt",
+}
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index 87fe831..706f636 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -16,42 +16,6 @@
LOCAL_PATH:= $(call my-dir)
-# Build the android.test.runner library
-# =====================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := \
- core-oj \
- core-libart \
- framework \
- android.test.base \
- android.test.mock \
-
-LOCAL_MODULE:= android.test.runner
-
-include $(BUILD_JAVA_LIBRARY)
-
-# Build the repackaged.android.test.runner library
-# ================================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := \
- core-oj \
- core-libart \
- framework \
- android.test.base \
- android.test.mock \
-
-LOCAL_JARJAR_RULES := $(LOCAL_PATH)/../test-base/jarjar-rules.txt
-
-LOCAL_MODULE:= repackaged.android.test.runner
-
-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)))
@@ -152,3 +116,6 @@
$(hide) $(ACP) $(ANDROID_TEST_RUNNER_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_RUNNER_REMOVED_API_FILE)
endif # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
+
+# additionally, build unit tests in a separate .apk
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/test-runner/jarjar-rules.txt b/test-runner/jarjar-rules.txt
new file mode 120000
index 0000000..f6f7913
--- /dev/null
+++ b/test-runner/jarjar-rules.txt
@@ -0,0 +1 @@
+../test-base/jarjar-rules.txt
\ No newline at end of file
diff --git a/test-runner/tests/Android.mk b/test-runner/tests/Android.mk
index 7ee047e4..1a4f6d5 100644
--- a/test-runner/tests/Android.mk
+++ b/test-runner/tests/Android.mk
@@ -25,8 +25,8 @@
#
LOCAL_MODULE_TAGS := tests
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
+LOCAL_STATIC_JAVA_LIBRARIES := junit
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
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/BrowserPowerTest/Android.mk b/tests/BrowserPowerTest/Android.mk
index 59bc729..5765575 100644
--- a/tests/BrowserPowerTest/Android.mk
+++ b/tests/BrowserPowerTest/Android.mk
@@ -18,8 +18,8 @@
# We only want this apk build for tests.
LOCAL_MODULE_TAGS := tests
-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 all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
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/CantSaveState1/Android.mk b/tests/CantSaveState1/Android.mk
deleted file mode 100644
index 6e9db6e..0000000
--- a/tests/CantSaveState1/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := CantSaveState1
-
-include $(BUILD_PACKAGE)
diff --git a/tests/CantSaveState1/AndroidManifest.xml b/tests/CantSaveState1/AndroidManifest.xml
deleted file mode 100644
index fadcaeb..0000000
--- a/tests/CantSaveState1/AndroidManifest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?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.test.cantsavestate1">
- <application android:label="Can't Save 1" android:cantSaveState="true">
- <activity android:name="CantSave1Activity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/CantSaveState1/res/layout/cant_save_1_activity.xml b/tests/CantSaveState1/res/layout/cant_save_1_activity.xml
deleted file mode 100644
index c5bf657..0000000
--- a/tests/CantSaveState1/res/layout/cant_save_1_activity.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
->
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="25dp"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:text="This app #1 can't save its state"
- />
-
-</LinearLayout>
diff --git a/tests/CantSaveState1/src/com/android/test/cantsavestate2/CantSave1Activity.java b/tests/CantSaveState1/src/com/android/test/cantsavestate2/CantSave1Activity.java
deleted file mode 100644
index 8879ed0..0000000
--- a/tests/CantSaveState1/src/com/android/test/cantsavestate2/CantSave1Activity.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.test.cantsavestate1;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class CantSave1Activity extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.cant_save_1_activity);
- }
-}
diff --git a/tests/CantSaveState2/Android.mk b/tests/CantSaveState2/Android.mk
deleted file mode 100644
index add9214..0000000
--- a/tests/CantSaveState2/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := CantSaveState2
-
-include $(BUILD_PACKAGE)
diff --git a/tests/CantSaveState2/res/layout/cant_save_2_activity.xml b/tests/CantSaveState2/res/layout/cant_save_2_activity.xml
deleted file mode 100644
index c5b8e3d..0000000
--- a/tests/CantSaveState2/res/layout/cant_save_2_activity.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
->
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="25dp"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:text="This app #2 can't save its state"
- />
-
-</LinearLayout>
diff --git a/tests/CanvasCompare/Android.mk b/tests/CanvasCompare/Android.mk
index 90de503..b071ec4 100644
--- a/tests/CanvasCompare/Android.mk
+++ b/tests/CanvasCompare/Android.mk
@@ -23,7 +23,7 @@
LOCAL_MODULE_TAGS := tests
-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_PACKAGE)
diff --git a/tests/CoreTests/android/Android.mk b/tests/CoreTests/android/Android.mk
index c9f1161..56d7918 100644
--- a/tests/CoreTests/android/Android.mk
+++ b/tests/CoreTests/android/Android.mk
@@ -6,8 +6,14 @@
LOCAL_SRC_FILES := \
$(call all-subdir-java-files)
-LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle conscrypt org.apache.http.legacy
-LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
+LOCAL_JAVA_LIBRARIES := \
+ android.test.runner \
+ bouncycastle \
+ conscrypt \
+ org.apache.http.legacy \
+ android.test.base \
+
+LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_PACKAGE_NAME := CoreTests
diff --git a/tests/DataIdleTest/Android.mk b/tests/DataIdleTest/Android.mk
index 4e15729..85f7edf 100644
--- a/tests/DataIdleTest/Android.mk
+++ b/tests/DataIdleTest/Android.mk
@@ -20,8 +20,8 @@
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := DataIdleTest
-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
LOCAL_SRC_FILES := $(call all-java-files-under, src)
# We need to sign it to get access to the network usage history.
diff --git a/tests/FrameworkPerf/Android.mk b/tests/FrameworkPerf/Android.mk
index d2ec753..1873cc1 100644
--- a/tests/FrameworkPerf/Android.mk
+++ b/tests/FrameworkPerf/Android.mk
@@ -7,8 +7,8 @@
LOCAL_PACKAGE_NAME := FrameworkPerf
-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
LOCAL_AAPT_FLAGS = -c 120dpi,240dpi,160dpi,161dpi,320dpi,nodpi
diff --git a/tests/HierarchyViewerTest/Android.mk b/tests/HierarchyViewerTest/Android.mk
index f8c8656..8550d70 100644
--- a/tests/HierarchyViewerTest/Android.mk
+++ b/tests/HierarchyViewerTest/Android.mk
@@ -7,7 +7,7 @@
LOCAL_PACKAGE_NAME := HierarchyViewerTest
-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_PACKAGE)
diff --git a/tests/ImfTest/tests/Android.mk b/tests/ImfTest/tests/Android.mk
index 6042471..a0df959 100644
--- a/tests/ImfTest/tests/Android.mk
+++ b/tests/ImfTest/tests/Android.mk
@@ -7,8 +7,8 @@
# Include all test java files.
LOCAL_SRC_FILES := $(call all-subdir-java-files)
-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
LOCAL_PACKAGE_NAME := ImfTestTests
diff --git a/tests/Internal/Android.mk b/tests/Internal/Android.mk
index fc001e9..73181ec 100644
--- a/tests/Internal/Android.mk
+++ b/tests/Internal/Android.mk
@@ -11,7 +11,6 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_STATIC_JAVA_LIBRARIES := junit \
- legacy-android-test \
android-support-test \
mockito-target-minus-junit4
diff --git a/tests/MemoryUsage/Android.mk b/tests/MemoryUsage/Android.mk
index 578e628..e186e9f 100644
--- a/tests/MemoryUsage/Android.mk
+++ b/tests/MemoryUsage/Android.mk
@@ -9,8 +9,8 @@
LOCAL_PACKAGE_NAME := MemoryUsage
LOCAL_CERTIFICATE := platform
-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_PACKAGE)
diff --git a/tests/NetworkSecurityConfigTest/Android.mk b/tests/NetworkSecurityConfigTest/Android.mk
index dd9ff11..6fb6025 100644
--- a/tests/NetworkSecurityConfigTest/Android.mk
+++ b/tests/NetworkSecurityConfigTest/Android.mk
@@ -5,8 +5,13 @@
LOCAL_MODULE_TAGS := tests
LOCAL_CERTIFICATE := platform
-LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle conscrypt
-LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
+LOCAL_JAVA_LIBRARIES := \
+ android.test.runner \
+ bouncycastle \
+ conscrypt \
+ android.test.base \
+
+LOCAL_STATIC_JAVA_LIBRARIES := junit
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
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/SoundTriggerTests/Android.mk b/tests/SoundTriggerTests/Android.mk
index 359484e..030d5f4 100644
--- a/tests/SoundTriggerTests/Android.mk
+++ b/tests/SoundTriggerTests/Android.mk
@@ -27,8 +27,8 @@
LOCAL_SRC_FILES := src/android/hardware/soundtrigger/SoundTriggerTest.java
endif
-LOCAL_STATIC_JAVA_LIBRARIES := mockito-target legacy-android-test
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_PACKAGE_NAME := SoundTriggerTests
diff --git a/tests/SurfaceComposition/Android.mk b/tests/SurfaceComposition/Android.mk
index d97c3f4..1962791 100644
--- a/tests/SurfaceComposition/Android.mk
+++ b/tests/SurfaceComposition/Android.mk
@@ -27,7 +27,9 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test junit
+LOCAL_STATIC_JAVA_LIBRARIES := junit
+
+LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
LOCAL_PACKAGE_NAME := SurfaceComposition
diff --git a/tests/TtsTests/Android.mk b/tests/TtsTests/Android.mk
index 3c3cd77..2fa1950 100644
--- a/tests/TtsTests/Android.mk
+++ b/tests/TtsTests/Android.mk
@@ -20,8 +20,8 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_STATIC_JAVA_LIBRARIES := mockito-target legacy-android-test
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_PACKAGE_NAME := TtsTests
diff --git a/tests/WindowAnimationJank/Android.mk b/tests/WindowAnimationJank/Android.mk
index f356afb..8aac8a1 100644
--- a/tests/WindowAnimationJank/Android.mk
+++ b/tests/WindowAnimationJank/Android.mk
@@ -27,7 +27,6 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
ub-uiautomator \
ub-janktesthelper \
- legacy-android-test \
junit
LOCAL_SDK_VERSION := current
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/OWNERS b/tests/net/OWNERS
index 2d71c20..6f77e04 100644
--- a/tests/net/OWNERS
+++ b/tests/net/OWNERS
@@ -1,10 +1,7 @@
set noparent
-per-file Android.mk = build.master@android.com
-per-file Android.mk = ek@google.com
-per-file Android.mk = hugobenichi@google.com
-per-file Android.mk = lorenzo@google.com
-
ek@google.com
hugobenichi@google.com
+jchalard@google.com
lorenzo@google.com
+satk@google.com
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/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/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 5c031eb..20a4897 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -22,7 +22,6 @@
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -39,6 +38,7 @@
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.support.test.filters.SmallTest;
+import android.system.Os;
import java.net.Socket;
import java.util.Arrays;
@@ -154,6 +154,56 @@
anyString(),
anyString(),
eq(TEST_SPI_OUT));
+
+ // Verify quota and RefcountedResource objects cleaned up
+ IpSecService.UserRecord userRecord =
+ mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+ assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
+ try {
+ userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
+ fail("Expected IllegalArgumentException on attempt to access deleted resource");
+ } catch (IllegalArgumentException expected) {
+
+ }
+ }
+
+ @Test
+ public void testSecurityParameterIndexBinderDeath() throws Exception {
+ when(mMockNetd.ipSecAllocateSpi(
+ anyInt(),
+ eq(IpSecTransform.DIRECTION_OUT),
+ anyString(),
+ eq(mRemoteAddr),
+ eq(TEST_SPI_OUT)))
+ .thenReturn(TEST_SPI_OUT);
+
+ IpSecSpiResponse spiResp =
+ mIpSecService.reserveSecurityParameterIndex(
+ IpSecTransform.DIRECTION_OUT, mRemoteAddr, TEST_SPI_OUT, new Binder());
+
+ IpSecService.UserRecord userRecord =
+ mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+ IpSecService.RefcountedResource refcountedRecord =
+ userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
+
+ refcountedRecord.binderDied();
+
+ verify(mMockNetd)
+ .ipSecDeleteSecurityAssociation(
+ eq(spiResp.resourceId),
+ anyInt(),
+ anyString(),
+ anyString(),
+ eq(TEST_SPI_OUT));
+
+ // Verify quota and RefcountedResource objects cleaned up
+ assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
+ try {
+ userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
+ fail("Expected IllegalArgumentException on attempt to access deleted resource");
+ } catch (IllegalArgumentException expected) {
+
+ }
}
private int getNewSpiResourceId(int direction, String remoteAddress, int returnSpi)
@@ -379,6 +429,61 @@
anyString(),
anyString(),
eq(TEST_SPI_IN));
+
+ // Verify quota and RefcountedResource objects cleaned up
+ IpSecService.UserRecord userRecord =
+ mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+ assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
+ try {
+ userRecord.mTransformRecords.getRefcountedResourceOrThrow(
+ createTransformResp.resourceId);
+ fail("Expected IllegalArgumentException on attempt to access deleted resource");
+ } catch (IllegalArgumentException expected) {
+
+ }
+ }
+
+ @Test
+ public void testTransportModeTransformBinderDeath() throws Exception {
+ IpSecConfig ipSecConfig = new IpSecConfig();
+ addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+ addAuthAndCryptToIpSecConfig(ipSecConfig);
+
+ IpSecTransformResponse createTransformResp =
+ mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
+
+ IpSecService.UserRecord userRecord =
+ mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+ IpSecService.RefcountedResource refcountedRecord =
+ userRecord.mTransformRecords.getRefcountedResourceOrThrow(
+ createTransformResp.resourceId);
+
+ refcountedRecord.binderDied();
+
+ verify(mMockNetd)
+ .ipSecDeleteSecurityAssociation(
+ eq(createTransformResp.resourceId),
+ eq(IpSecTransform.DIRECTION_OUT),
+ anyString(),
+ anyString(),
+ eq(TEST_SPI_OUT));
+ verify(mMockNetd)
+ .ipSecDeleteSecurityAssociation(
+ eq(createTransformResp.resourceId),
+ eq(IpSecTransform.DIRECTION_IN),
+ anyString(),
+ anyString(),
+ eq(TEST_SPI_IN));
+
+ // Verify quota and RefcountedResource objects cleaned up
+ assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
+ try {
+ userRecord.mTransformRecords.getRefcountedResourceOrThrow(
+ createTransformResp.resourceId);
+ fail("Expected IllegalArgumentException on attempt to access deleted resource");
+ } catch (IllegalArgumentException expected) {
+
+ }
}
@Test
diff --git a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
new file mode 100644
index 0000000..cf8f715
--- /dev/null
+++ b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
@@ -0,0 +1,356 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doThrow;
+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 android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.server.IpSecService.IResource;
+import com.android.server.IpSecService.RefcountedResource;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit tests for {@link IpSecService.RefcountedResource}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class IpSecServiceRefcountedResourceTest {
+ Context mMockContext;
+ IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
+ IpSecService mIpSecService;
+
+ @Before
+ public void setUp() throws Exception {
+ mMockContext = mock(Context.class);
+ mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
+ mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
+ }
+
+ private void assertResourceState(
+ RefcountedResource<IResource> resource,
+ int refCount,
+ int userReleaseCallCount,
+ int releaseReferenceCallCount,
+ int invalidateCallCount,
+ int freeUnderlyingResourcesCallCount)
+ throws RemoteException {
+ // Check refcount on RefcountedResource
+ assertEquals(refCount, resource.mRefCount);
+
+ // Check call count of RefcountedResource
+ verify(resource, times(userReleaseCallCount)).userRelease();
+ verify(resource, times(releaseReferenceCallCount)).releaseReference();
+
+ // Check call count of IResource
+ verify(resource.getResource(), times(invalidateCallCount)).invalidate();
+ verify(resource.getResource(), times(freeUnderlyingResourcesCallCount))
+ .freeUnderlyingResources();
+ }
+
+ /** Adds mockito instrumentation */
+ private RefcountedResource<IResource> getTestRefcountedResource(
+ RefcountedResource... children) {
+ return getTestRefcountedResource(new Binder(), children);
+ }
+
+ /** Adds mockito instrumentation with provided binder */
+ private RefcountedResource<IResource> getTestRefcountedResource(
+ IBinder binder, RefcountedResource... children) {
+ return spy(
+ mIpSecService
+ .new RefcountedResource<IResource>(mock(IResource.class), binder, children));
+ }
+
+ @Test
+ public void testConstructor() throws RemoteException {
+ IBinder binderMock = mock(IBinder.class);
+ RefcountedResource<IResource> resource = getTestRefcountedResource(binderMock);
+
+ // Verify resource's refcount starts at 1 (for user-reference)
+ assertResourceState(resource, 1, 0, 0, 0, 0);
+
+ // Verify linking to binder death
+ verify(binderMock).linkToDeath(anyObject(), anyInt());
+ }
+
+ @Test
+ public void testConstructorWithChildren() throws RemoteException {
+ IBinder binderMockChild = mock(IBinder.class);
+ IBinder binderMockParent = mock(IBinder.class);
+ RefcountedResource<IResource> childResource = getTestRefcountedResource(binderMockChild);
+ RefcountedResource<IResource> parentResource =
+ getTestRefcountedResource(binderMockParent, childResource);
+
+ // Verify parent's refcount starts at 1 (for user-reference)
+ assertResourceState(parentResource, 1, 0, 0, 0, 0);
+
+ // Verify child's refcounts were incremented
+ assertResourceState(childResource, 2, 0, 0, 0, 0);
+
+ // Verify linking to binder death
+ verify(binderMockChild).linkToDeath(anyObject(), anyInt());
+ verify(binderMockParent).linkToDeath(anyObject(), anyInt());
+ }
+
+ @Test
+ public void testFailLinkToDeath() throws RemoteException {
+ IBinder binderMock = mock(IBinder.class);
+ doThrow(new RemoteException()).when(binderMock).linkToDeath(anyObject(), anyInt());
+
+ RefcountedResource<IResource> refcountedResource = getTestRefcountedResource(binderMock);
+
+ // Verify that cleanup is performed (Spy limitations prevent verification of method calls
+ // for binder death scenario; check refcount to determine if cleanup was performed.)
+ assertEquals(-1, refcountedResource.mRefCount);
+ }
+
+ @Test
+ public void testCleanupAndRelease() throws RemoteException {
+ IBinder binderMock = mock(IBinder.class);
+ RefcountedResource<IResource> refcountedResource = getTestRefcountedResource(binderMock);
+
+ // Verify user-initiated cleanup path decrements refcount and calls full cleanup flow
+ refcountedResource.userRelease();
+ assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
+
+ // Verify user-initated cleanup path unlinks from binder
+ verify(binderMock).unlinkToDeath(eq(refcountedResource), eq(0));
+ assertNull(refcountedResource.mBinder);
+ }
+
+ @Test
+ public void testMultipleCallsToCleanupAndRelease() throws RemoteException {
+ RefcountedResource<IResource> refcountedResource = getTestRefcountedResource();
+
+ // Verify calling userRelease multiple times does not trigger any other cleanup
+ // methods
+ refcountedResource.userRelease();
+ assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
+
+ refcountedResource.userRelease();
+ refcountedResource.userRelease();
+ assertResourceState(refcountedResource, -1, 3, 1, 1, 1);
+ }
+
+ @Test
+ public void testBinderDeathAfterCleanupAndReleaseDoesNothing() throws RemoteException {
+ RefcountedResource<IResource> refcountedResource = getTestRefcountedResource();
+
+ refcountedResource.userRelease();
+ assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
+
+ // Verify binder death call does not trigger any other cleanup methods if called after
+ // userRelease()
+ refcountedResource.binderDied();
+ assertResourceState(refcountedResource, -1, 2, 1, 1, 1);
+ }
+
+ @Test
+ public void testBinderDeath() throws RemoteException {
+ RefcountedResource<IResource> refcountedResource = getTestRefcountedResource();
+
+ // Verify binder death caused cleanup
+ refcountedResource.binderDied();
+ verify(refcountedResource, times(1)).binderDied();
+ assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
+ assertNull(refcountedResource.mBinder);
+ }
+
+ @Test
+ public void testCleanupParentDecrementsChildRefcount() throws RemoteException {
+ RefcountedResource<IResource> childResource = getTestRefcountedResource();
+ RefcountedResource<IResource> parentResource = getTestRefcountedResource(childResource);
+
+ parentResource.userRelease();
+
+ // Verify parent gets cleaned up properly, and triggers releaseReference on
+ // child
+ assertResourceState(childResource, 1, 0, 1, 0, 0);
+ assertResourceState(parentResource, -1, 1, 1, 1, 1);
+ }
+
+ @Test
+ public void testCleanupReferencedChildDoesNotTriggerRelease() throws RemoteException {
+ RefcountedResource<IResource> childResource = getTestRefcountedResource();
+ RefcountedResource<IResource> parentResource = getTestRefcountedResource(childResource);
+
+ childResource.userRelease();
+
+ // Verify that child does not clean up kernel resources and quota.
+ assertResourceState(childResource, 1, 1, 1, 1, 0);
+ assertResourceState(parentResource, 1, 0, 0, 0, 0);
+ }
+
+ @Test
+ public void testTwoParents() throws RemoteException {
+ RefcountedResource<IResource> childResource = getTestRefcountedResource();
+ RefcountedResource<IResource> parentResource1 = getTestRefcountedResource(childResource);
+ RefcountedResource<IResource> parentResource2 = getTestRefcountedResource(childResource);
+
+ // Verify that child does not cleanup kernel resources and quota until all references
+ // have been released. Assumption: parents release correctly based on
+ // testCleanupParentDecrementsChildRefcount()
+ childResource.userRelease();
+ assertResourceState(childResource, 2, 1, 1, 1, 0);
+
+ parentResource1.userRelease();
+ assertResourceState(childResource, 1, 1, 2, 1, 0);
+
+ parentResource2.userRelease();
+ assertResourceState(childResource, -1, 1, 3, 1, 1);
+ }
+
+ @Test
+ public void testTwoChildren() throws RemoteException {
+ RefcountedResource<IResource> childResource1 = getTestRefcountedResource();
+ RefcountedResource<IResource> childResource2 = getTestRefcountedResource();
+ RefcountedResource<IResource> parentResource =
+ getTestRefcountedResource(childResource1, childResource2);
+
+ childResource1.userRelease();
+ assertResourceState(childResource1, 1, 1, 1, 1, 0);
+ assertResourceState(childResource2, 2, 0, 0, 0, 0);
+
+ parentResource.userRelease();
+ assertResourceState(childResource1, -1, 1, 2, 1, 1);
+ assertResourceState(childResource2, 1, 0, 1, 0, 0);
+
+ childResource2.userRelease();
+ assertResourceState(childResource1, -1, 1, 2, 1, 1);
+ assertResourceState(childResource2, -1, 1, 2, 1, 1);
+ }
+
+ @Test
+ public void testSampleUdpEncapTranform() throws RemoteException {
+ RefcountedResource<IResource> spi1 = getTestRefcountedResource();
+ RefcountedResource<IResource> spi2 = getTestRefcountedResource();
+ RefcountedResource<IResource> udpEncapSocket = getTestRefcountedResource();
+ RefcountedResource<IResource> transform =
+ getTestRefcountedResource(spi1, spi2, udpEncapSocket);
+
+ // Pretend one SPI goes out of reference (releaseManagedResource -> userRelease)
+ spi1.userRelease();
+
+ // User called releaseManagedResource on udpEncap socket
+ udpEncapSocket.userRelease();
+
+ // User dies, and binder kills the rest
+ spi2.binderDied();
+ transform.binderDied();
+
+ // Check resource states
+ assertResourceState(spi1, -1, 1, 2, 1, 1);
+ assertResourceState(spi2, -1, 1, 2, 1, 1);
+ assertResourceState(udpEncapSocket, -1, 1, 2, 1, 1);
+ assertResourceState(transform, -1, 1, 1, 1, 1);
+ }
+
+ @Test
+ public void testSampleDualTransformEncapSocket() throws RemoteException {
+ RefcountedResource<IResource> spi1 = getTestRefcountedResource();
+ RefcountedResource<IResource> spi2 = getTestRefcountedResource();
+ RefcountedResource<IResource> spi3 = getTestRefcountedResource();
+ RefcountedResource<IResource> spi4 = getTestRefcountedResource();
+ RefcountedResource<IResource> udpEncapSocket = getTestRefcountedResource();
+ RefcountedResource<IResource> transform1 =
+ getTestRefcountedResource(spi1, spi2, udpEncapSocket);
+ RefcountedResource<IResource> transform2 =
+ getTestRefcountedResource(spi3, spi4, udpEncapSocket);
+
+ // Pretend one SPIs goes out of reference (releaseManagedResource -> userRelease)
+ spi1.userRelease();
+
+ // User called releaseManagedResource on udpEncap socket and spi4
+ udpEncapSocket.userRelease();
+ spi4.userRelease();
+
+ // User dies, and binder kills the rest
+ spi2.binderDied();
+ spi3.binderDied();
+ transform2.binderDied();
+ transform1.binderDied();
+
+ // Check resource states
+ assertResourceState(spi1, -1, 1, 2, 1, 1);
+ assertResourceState(spi2, -1, 1, 2, 1, 1);
+ assertResourceState(spi3, -1, 1, 2, 1, 1);
+ assertResourceState(spi4, -1, 1, 2, 1, 1);
+ assertResourceState(udpEncapSocket, -1, 1, 3, 1, 1);
+ assertResourceState(transform1, -1, 1, 1, 1, 1);
+ assertResourceState(transform2, -1, 1, 1, 1, 1);
+ }
+
+ @Test
+ public void fuzzTest() throws RemoteException {
+ List<RefcountedResource<IResource>> resources = new ArrayList<>();
+
+ // Build a tree of resources
+ for (int i = 0; i < 100; i++) {
+ // Choose a random number of children from the existing list
+ int numChildren = ThreadLocalRandom.current().nextInt(0, resources.size() + 1);
+
+ // Build a (random) list of children
+ Set<RefcountedResource<IResource>> children = new HashSet<>();
+ for (int j = 0; j < numChildren; j++) {
+ int childIndex = ThreadLocalRandom.current().nextInt(0, resources.size());
+ children.add(resources.get(childIndex));
+ }
+
+ RefcountedResource<IResource> newRefcountedResource =
+ getTestRefcountedResource(
+ children.toArray(new RefcountedResource[children.size()]));
+ resources.add(newRefcountedResource);
+ }
+
+ // Cleanup all resources in a random order
+ List<RefcountedResource<IResource>> clonedResources =
+ new ArrayList<>(resources); // shallow copy
+ while (!clonedResources.isEmpty()) {
+ int index = ThreadLocalRandom.current().nextInt(0, clonedResources.size());
+ RefcountedResource<IResource> refcountedResource = clonedResources.get(index);
+ refcountedResource.userRelease();
+ clonedResources.remove(index);
+ }
+
+ // Verify all resources were cleaned up properly
+ for (RefcountedResource<IResource> refcountedResource : resources) {
+ assertEquals(-1, refcountedResource.mRefCount);
+ }
+ }
+}
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index 8e579aa..354ad2a 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -131,7 +131,39 @@
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
udpEncapResp.fileDescriptor.close();
- // TODO: Added check for the resource tracker
+ IpSecService.UserRecord userRecord =
+ mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+ assertEquals(0, userRecord.mSocketQuotaTracker.mCurrent);
+ try {
+ userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(udpEncapResp.resourceId);
+ fail("Expected IllegalArgumentException on attempt to access deleted resource");
+ } catch (IllegalArgumentException expected) {
+
+ }
+ }
+
+ @Test
+ public void testUdpEncapsulationSocketBinderDeath() throws Exception {
+ int localport = findUnusedPort();
+
+ IpSecUdpEncapResponse udpEncapResp =
+ mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+
+ IpSecService.UserRecord userRecord =
+ mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+ IpSecService.RefcountedResource refcountedRecord =
+ userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(
+ udpEncapResp.resourceId);
+
+ refcountedRecord.binderDied();
+
+ assertEquals(0, userRecord.mSocketQuotaTracker.mCurrent);
+ try {
+ userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(udpEncapResp.resourceId);
+ fail("Expected IllegalArgumentException on attempt to access deleted resource");
+ } catch (IllegalArgumentException expected) {
+
+ }
}
@Test
@@ -270,8 +302,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 +319,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 +330,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 +349,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/permission/Android.mk b/tests/permission/Android.mk
index 54688c8..7f81d9a3 100644
--- a/tests/permission/Android.mk
+++ b/tests/permission/Android.mk
@@ -7,8 +7,8 @@
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
-LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
+LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.test.base
+LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_PACKAGE_NAME := FrameworkPermissionTests
include $(BUILD_PACKAGE)
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/tests/Android.mk b/tests/testables/tests/Android.mk
index 16fe535..6e20d797 100644
--- a/tests/testables/tests/Android.mk
+++ b/tests/testables/tests/Android.mk
@@ -28,10 +28,9 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
mockito-target-minus-junit4 \
- legacy-android-test \
testables
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
LOCAL_CERTIFICATE := platform
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..20a9f41 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -43,42 +43,44 @@
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(
const Source& source, unique_ptr<io::IFileCollection> collection, IDiagnostics* diag) {
+ std::unique_ptr<ResourceTable> table;
+
io::IFile* table_file = collection->FindFile(kProtoResourceTablePath);
- if (table_file == nullptr) {
- diag->Error(DiagMessage(source) << "failed to find " << kProtoResourceTablePath);
- return {};
- }
+ if (table_file != nullptr) {
+ pb::ResourceTable pb_table;
+ std::unique_ptr<io::InputStream> in = table_file->OpenInputStream();
+ if (in == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to open " << kProtoResourceTablePath);
+ return {};
+ }
- std::unique_ptr<io::InputStream> in = table_file->OpenInputStream();
- if (in == nullptr) {
- diag->Error(DiagMessage(source) << "failed to open " << kProtoResourceTablePath);
- return {};
- }
+ io::ZeroCopyInputAdaptor adaptor(in.get());
+ if (!pb_table.ParseFromZeroCopyStream(&adaptor)) {
+ diag->Error(DiagMessage(source) << "failed to read " << kProtoResourceTablePath);
+ return {};
+ }
- pb::ResourceTable pb_table;
- io::ZeroCopyInputAdaptor adaptor(in.get());
- if (!pb_table.ParseFromZeroCopyStream(&adaptor)) {
- diag->Error(DiagMessage(source) << "failed to read " << kProtoResourceTablePath);
- return {};
- }
-
- std::string error;
- std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
- if (!DeserializeTableFromPb(pb_table, collection.get(), table.get(), &error)) {
- diag->Error(DiagMessage(source)
- << "failed to deserialize " << kProtoResourceTablePath << ": " << error);
- return {};
+ std::string error;
+ table = util::make_unique<ResourceTable>();
+ if (!DeserializeTableFromPb(pb_table, collection.get(), table.get(), &error)) {
+ diag->Error(DiagMessage(source)
+ << "failed to deserialize " << kProtoResourceTablePath << ": " << error);
+ return {};
+ }
}
io::IFile* manifest_file = collection->FindFile(kAndroidManifestPath);
@@ -100,6 +102,7 @@
return {};
}
+ std::string error;
std::unique_ptr<xml::XmlResource> manifest = DeserializeXmlResourceFromPb(pb_node, &error);
if (manifest == nullptr) {
diag->Error(DiagMessage(source)
@@ -112,24 +115,21 @@
std::unique_ptr<LoadedApk> LoadedApk::LoadBinaryApkFromFileCollection(
const Source& source, unique_ptr<io::IFileCollection> collection, IDiagnostics* diag) {
+ std::unique_ptr<ResourceTable> table;
+
io::IFile* table_file = collection->FindFile(kApkResourceTablePath);
- if (table_file == nullptr) {
- diag->Error(DiagMessage(source) << "failed to find " << kApkResourceTablePath);
-
- return {};
- }
-
- std::unique_ptr<io::IData> data = table_file->OpenAsData();
- if (data == nullptr) {
- diag->Error(DiagMessage(source) << "failed to open " << kApkResourceTablePath);
- return {};
- }
-
- std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
- BinaryResourceParser parser(diag, table.get(), source, data->data(), data->size(),
- collection.get());
- if (!parser.Parse()) {
- return {};
+ if (table_file != nullptr) {
+ table = util::make_unique<ResourceTable>();
+ std::unique_ptr<io::IData> data = table_file->OpenAsData();
+ if (data == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to open " << kApkResourceTablePath);
+ return {};
+ }
+ BinaryResourceParser parser(diag, table.get(), source, data->data(), data->size(),
+ collection.get());
+ if (!parser.Parse()) {
+ return {};
+ }
}
io::IFile* manifest_file = collection->FindFile(kAndroidManifestPath);
@@ -243,4 +243,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/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 2bd2405..964dacf 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -64,37 +64,39 @@
return false;
}
- // Resource table
- if (!serializer->SerializeTable(apk->GetResourceTable(), writer)) {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
- << "failed to serialize the resource table");
- return false;
+ if (apk->GetResourceTable() != nullptr) {
+ // Resource table
+ if (!serializer->SerializeTable(apk->GetResourceTable(), writer)) {
+ context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ << "failed to serialize the resource table");
+ return false;
+ }
+
+ // Resources
+ for (const auto& package : apk->GetResourceTable()->packages) {
+ for (const auto& type : package->types) {
+ for (const auto& entry : type->entries) {
+ for (const auto& config_value : entry->values) {
+ const FileReference* file = ValueCast<FileReference>(config_value->value.get());
+ if (file != nullptr) {
+ if (file->file == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ << "no file associated with " << *file);
+ return false;
+ }
+
+ if (!serializer->SerializeFile(file, writer)) {
+ context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ << "failed to serialize file " << *file->path);
+ return false;
+ }
+ } // file
+ } // config_value
+ } // entry
+ } // type
+ } // package
}
- // Resources
- for (const auto& package : apk->GetResourceTable()->packages) {
- for (const auto& type : package->types) {
- for (const auto& entry : type->entries) {
- for (const auto& config_value : entry->values) {
- const FileReference* file = ValueCast<FileReference>(config_value->value.get());
- if (file != nullptr) {
- if (file->file == nullptr) {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
- << "no file associated with " << *file);
- return false;
- }
-
- if (!serializer->SerializeFile(file, writer)) {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
- << "failed to serialize file " << *file->path);
- return false;
- }
- } // file
- } // config_value
- } // entry
- } // type
- } // package
-
// Other files
std::unique_ptr<io::IFileCollectionIterator> iterator = apk->GetFileCollection()->Iterator();
while (iterator->HasNext()) {
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index e94c0b4..d782de5 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());
+ }
}
}
@@ -974,25 +1069,29 @@
bool WriteJavaFile(ResourceTable* table, const StringPiece& package_name_to_generate,
const StringPiece& out_package, const JavaClassGeneratorOptions& java_options,
const Maybe<std::string>& out_text_symbols_path = {}) {
- if (!options_.generate_java_class_path) {
+ if (!options_.generate_java_class_path && !out_text_symbols_path) {
return true;
}
- std::string out_path = options_.generate_java_class_path.value();
- file::AppendPath(&out_path, file::PackageToPath(out_package));
- if (!file::mkdirs(out_path)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to create directory '" << out_path
- << "'");
- return false;
- }
+ std::string out_path;
+ std::unique_ptr<io::FileOutputStream> fout;
+ if (options_.generate_java_class_path) {
+ out_path = options_.generate_java_class_path.value();
+ file::AppendPath(&out_path, file::PackageToPath(out_package));
+ if (!file::mkdirs(out_path)) {
+ context_->GetDiagnostics()->Error(DiagMessage()
+ << "failed to create directory '" << out_path << "'");
+ return false;
+ }
- file::AppendPath(&out_path, "R.java");
+ file::AppendPath(&out_path, "R.java");
- io::FileOutputStream fout(out_path);
- if (fout.HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
- << "': " << fout.GetError());
- return false;
+ fout = util::make_unique<io::FileOutputStream>(out_path);
+ if (fout->HadError()) {
+ context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
+ << "': " << fout->GetError());
+ return false;
+ }
}
std::unique_ptr<io::FileOutputStream> fout_text;
@@ -1007,18 +1106,11 @@
}
JavaClassGenerator generator(context_, table, java_options);
- if (!generator.Generate(package_name_to_generate, out_package, &fout, fout_text.get())) {
+ if (!generator.Generate(package_name_to_generate, out_package, fout.get(), fout_text.get())) {
context_->GetDiagnostics()->Error(DiagMessage(out_path) << generator.GetError());
return false;
}
- fout.Flush();
-
- if (fout.HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
- << "': " << fout.GetError());
- return false;
- }
return true;
}
@@ -1235,19 +1327,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 +1342,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 +1353,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 +1626,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 +1660,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 +1671,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");
@@ -1820,7 +1931,7 @@
return 1;
}
- if (options_.generate_java_class_path) {
+ if (options_.generate_java_class_path || options_.generate_text_symbols_path) {
if (!GenerateJavaClasses()) {
return 1;
}
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 2bf91a5..d8bb999 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"
@@ -43,10 +44,10 @@
#include "util/Util.h"
using ::aapt::configuration::Abi;
-using ::aapt::configuration::Artifact;
-using ::aapt::configuration::PostProcessingConfiguration;
+using ::aapt::configuration::OutputArtifact;
using ::android::ResTable_config;
using ::android::StringPiece;
+using ::android::base::ReadFileToString;
using ::android::base::StringAppendF;
using ::android::base::StringPrintf;
@@ -72,7 +73,11 @@
TableFlattenerOptions table_flattener_options;
- Maybe<PostProcessingConfiguration> configuration;
+ Maybe<std::vector<OutputArtifact>> apk_artifacts;
+
+ // 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 {
@@ -193,11 +198,11 @@
++split_constraints_iter;
}
- if (options_.configuration && options_.output_dir) {
+ if (options_.apk_artifacts && 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_.apk_artifacts.value(),
+ options_.table_flattener_options, options_.kept_artifacts};
if (!generator.FromBaseApk(generator_options)) {
return 1;
}
@@ -279,6 +284,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 +321,11 @@
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,12 +340,10 @@
"All the resources that would be unused on devices of the given densities will be \n"
"removed from the APK.",
&target_densities)
- .OptionalFlag(
- "--target-abis",
- "Comma separated list of the CPU ABIs that the APK will be optimized for.\n"
- "All the native libraries that would be unused on devices of the given ABIs will \n"
- "be removed from the APK.",
- &target_abis)
+ .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)
.OptionalFlagList("-c",
"Comma separated list of configurations to include. The default\n"
"is all configurations.",
@@ -335,10 +353,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)) {
@@ -394,26 +419,32 @@
std::string& path = config_path.value();
Maybe<ConfigurationParser> for_path = ConfigurationParser::ForPath(path);
if (for_path) {
- options.configuration = for_path.value().WithDiagnostics(diag).Parse();
+ options.apk_artifacts = for_path.value().WithDiagnostics(diag).Parse(apk_path);
+ if (!options.apk_artifacts) {
+ diag->Error(DiagMessage() << "Failed to parse the output artifact list");
+ return 1;
+ }
+
} else {
diag->Error(DiagMessage() << "Could not parse config file " << path);
return 1;
}
if (print_only) {
- std::vector<std::string> names;
- const PostProcessingConfiguration& config = options.configuration.value();
- if (!config.AllArtifactNames(file::GetFilename(apk_path), &names, diag)) {
- diag->Error(DiagMessage() << "Failed to generate output artifact list");
- return 1;
- }
-
- for (const auto& name : names) {
- std::cout << name << std::endl;
+ for (const OutputArtifact& artifact : options.apk_artifacts.value()) {
+ std::cout << artifact.name << std::endl;
}
return 0;
}
+ if (!kept_artifacts.empty()) {
+ for (const std::string& artifact_str : kept_artifacts) {
+ for (const StringPiece& 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 +456,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/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp
index b99240f..ebc523f 100644
--- a/tools/aapt2/configuration/ConfigurationParser.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser.cpp
@@ -28,6 +28,7 @@
#include "ConfigDescription.h"
#include "Diagnostics.h"
#include "ResourceUtils.h"
+#include "configuration/ConfigurationParser.internal.h"
#include "io/File.h"
#include "io/FileSystem.h"
#include "io/StringStream.h"
@@ -45,11 +46,22 @@
using ::aapt::configuration::Abi;
using ::aapt::configuration::AndroidManifest;
using ::aapt::configuration::AndroidSdk;
-using ::aapt::configuration::Artifact;
-using ::aapt::configuration::PostProcessingConfiguration;
+using ::aapt::configuration::ConfiguredArtifact;
+using ::aapt::configuration::DeviceFeature;
+using ::aapt::configuration::Entry;
using ::aapt::configuration::GlTexture;
using ::aapt::configuration::Group;
using ::aapt::configuration::Locale;
+using ::aapt::configuration::OutputArtifact;
+using ::aapt::configuration::PostProcessingConfiguration;
+using ::aapt::configuration::handler::AbiGroupTagHandler;
+using ::aapt::configuration::handler::AndroidSdkGroupTagHandler;
+using ::aapt::configuration::handler::ArtifactFormatTagHandler;
+using ::aapt::configuration::handler::ArtifactTagHandler;
+using ::aapt::configuration::handler::DeviceFeatureGroupTagHandler;
+using ::aapt::configuration::handler::GlTextureGroupTagHandler;
+using ::aapt::configuration::handler::LocaleGroupTagHandler;
+using ::aapt::configuration::handler::ScreenDensityGroupTagHandler;
using ::aapt::io::IFile;
using ::aapt::io::RegularFile;
using ::aapt::io::StringInputStream;
@@ -59,19 +71,16 @@
using ::aapt::xml::XmlActionExecutor;
using ::aapt::xml::XmlActionExecutorPolicy;
using ::aapt::xml::XmlNodeAction;
-using ::android::base::ReadFileToString;
using ::android::StringPiece;
+using ::android::base::ReadFileToString;
-const std::unordered_map<std::string, Abi> kStringToAbiMap = {
+const std::unordered_map<StringPiece, Abi> kStringToAbiMap = {
{"armeabi", Abi::kArmeV6}, {"armeabi-v7a", Abi::kArmV7a}, {"arm64-v8a", Abi::kArm64V8a},
{"x86", Abi::kX86}, {"x86_64", Abi::kX86_64}, {"mips", Abi::kMips},
{"mips64", Abi::kMips64}, {"universal", Abi::kUniversal},
};
-const std::map<Abi, std::string> kAbiToStringMap = {
- {Abi::kArmeV6, "armeabi"}, {Abi::kArmV7a, "armeabi-v7a"}, {Abi::kArm64V8a, "arm64-v8a"},
- {Abi::kX86, "x86"}, {Abi::kX86_64, "x86_64"}, {Abi::kMips, "mips"},
- {Abi::kMips64, "mips64"}, {Abi::kUniversal, "universal"},
-};
+const std::array<StringPiece, 8> kAbiToStringMap = {
+ {"armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64", "mips", "mips64", "universal"}};
constexpr const char* kAaptXmlNs = "http://schemas.android.com/tools/aapt";
@@ -106,12 +115,25 @@
}
};
-} // namespace
+/** Copies the values referenced in a configuration group to the target list. */
+template <typename T>
+bool CopyXmlReferences(const Maybe<std::string>& name, const Group<T>& groups,
+ std::vector<T>* target) {
+ // If there was no item configured, there is nothing to do and no error.
+ if (!name) {
+ return true;
+ }
-namespace configuration {
+ // If the group could not be found, then something is wrong.
+ auto group = groups.find(name.value());
+ if (group == groups.end()) {
+ return false;
+ }
-const std::string& AbiToString(Abi abi) {
- return kAbiToStringMap.find(abi)->second;
+ for (const T& item : group->second) {
+ target->push_back(item);
+ }
+ return true;
}
/**
@@ -119,8 +141,8 @@
* success, or false if the either the placeholder is not found in the name, or the value is not
* present and the placeholder was.
*/
-static bool ReplacePlaceholder(const StringPiece& placeholder, const Maybe<StringPiece>& value,
- std::string* name, IDiagnostics* diag) {
+bool ReplacePlaceholder(const StringPiece& placeholder, const Maybe<StringPiece>& value,
+ std::string* name, IDiagnostics* diag) {
size_t offset = name->find(placeholder.data());
bool found = (offset != std::string::npos);
@@ -152,6 +174,160 @@
}
/**
+ * An ActionHandler for processing XML elements in the XmlActionExecutor. Returns true if the
+ * element was successfully processed, otherwise returns false.
+ */
+using ActionHandler = std::function<bool(configuration::PostProcessingConfiguration* config,
+ xml::Element* element, IDiagnostics* diag)>;
+
+/** Binds an ActionHandler to the current configuration being populated. */
+xml::XmlNodeAction::ActionFuncWithDiag Bind(configuration::PostProcessingConfiguration* config,
+ const ActionHandler& handler) {
+ return [config, handler](xml::Element* root_element, SourcePathDiagnostics* diag) {
+ return handler(config, root_element, diag);
+ };
+}
+
+/** Returns the binary reprasentation of the XML configuration. */
+Maybe<PostProcessingConfiguration> ExtractConfiguration(const std::string& contents,
+ IDiagnostics* diag) {
+ StringInputStream in(contents);
+ std::unique_ptr<xml::XmlResource> doc = xml::Inflate(&in, diag, Source("config.xml"));
+ if (!doc) {
+ return {};
+ }
+
+ // Strip any namespaces from the XML as the XmlActionExecutor ignores anything with a namespace.
+ Element* root = doc->root.get();
+ if (root == nullptr) {
+ diag->Error(DiagMessage() << "Could not find the root element in the XML document");
+ return {};
+ }
+
+ std::string& xml_ns = root->namespace_uri;
+ if (!xml_ns.empty()) {
+ if (xml_ns != kAaptXmlNs) {
+ diag->Error(DiagMessage() << "Unknown namespace found on root element: " << xml_ns);
+ return {};
+ }
+
+ xml_ns.clear();
+ NamespaceVisitor visitor;
+ root->Accept(&visitor);
+ }
+
+ XmlActionExecutor executor;
+ XmlNodeAction& root_action = executor["post-process"];
+ XmlNodeAction& artifacts_action = root_action["artifacts"];
+ XmlNodeAction& groups_action = root_action["groups"];
+
+ PostProcessingConfiguration config;
+
+ // Parse the artifact elements.
+ artifacts_action["artifact"].Action(Bind(&config, ArtifactTagHandler));
+ artifacts_action["artifact-format"].Action(Bind(&config, ArtifactFormatTagHandler));
+
+ // Parse the different configuration groups.
+ groups_action["abi-group"].Action(Bind(&config, AbiGroupTagHandler));
+ groups_action["screen-density-group"].Action(Bind(&config, ScreenDensityGroupTagHandler));
+ groups_action["locale-group"].Action(Bind(&config, LocaleGroupTagHandler));
+ groups_action["android-sdk-group"].Action(Bind(&config, AndroidSdkGroupTagHandler));
+ groups_action["gl-texture-group"].Action(Bind(&config, GlTextureGroupTagHandler));
+ groups_action["device-feature-group"].Action(Bind(&config, DeviceFeatureGroupTagHandler));
+
+ if (!executor.Execute(XmlActionExecutorPolicy::kNone, diag, doc.get())) {
+ diag->Error(DiagMessage() << "Could not process XML document");
+ return {};
+ }
+
+ return {config};
+}
+
+/** Converts a ConfiguredArtifact into an OutputArtifact. */
+Maybe<OutputArtifact> ToOutputArtifact(const ConfiguredArtifact& artifact,
+ const std::string& apk_name,
+ const PostProcessingConfiguration& config,
+ IDiagnostics* diag) {
+ if (!artifact.name && !config.artifact_format) {
+ diag->Error(
+ DiagMessage() << "Artifact does not have a name and no global name template defined");
+ return {};
+ }
+
+ Maybe<std::string> 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");
+ return {};
+ }
+
+ OutputArtifact output_artifact;
+ output_artifact.name = artifact_name.value();
+
+ SourcePathDiagnostics src_diag{{output_artifact.name}, diag};
+ bool has_errors = false;
+
+ if (!CopyXmlReferences(artifact.abi_group, config.abi_groups, &output_artifact.abis)) {
+ src_diag.Error(DiagMessage() << "Could not lookup required ABIs: "
+ << artifact.abi_group.value());
+ has_errors = true;
+ }
+
+ if (!CopyXmlReferences(artifact.locale_group, config.locale_groups, &output_artifact.locales)) {
+ src_diag.Error(DiagMessage() << "Could not lookup required locales: "
+ << artifact.locale_group.value());
+ has_errors = true;
+ }
+
+ if (!CopyXmlReferences(artifact.screen_density_group, config.screen_density_groups,
+ &output_artifact.screen_densities)) {
+ src_diag.Error(DiagMessage() << "Could not lookup required screen densities: "
+ << artifact.screen_density_group.value());
+ has_errors = true;
+ }
+
+ if (!CopyXmlReferences(artifact.device_feature_group, config.device_feature_groups,
+ &output_artifact.features)) {
+ src_diag.Error(DiagMessage() << "Could not lookup required device features: "
+ << artifact.device_feature_group.value());
+ has_errors = true;
+ }
+
+ if (!CopyXmlReferences(artifact.gl_texture_group, config.gl_texture_groups,
+ &output_artifact.textures)) {
+ src_diag.Error(DiagMessage() << "Could not lookup required OpenGL texture formats: "
+ << artifact.gl_texture_group.value());
+ has_errors = true;
+ }
+
+ if (artifact.android_sdk_group) {
+ auto entry = config.android_sdk_groups.find(artifact.android_sdk_group.value());
+ if (entry == config.android_sdk_groups.end()) {
+ src_diag.Error(DiagMessage() << "Could not lookup required Android SDK version: "
+ << artifact.android_sdk_group.value());
+ has_errors = true;
+ } else {
+ output_artifact.android_sdk = {entry->second};
+ }
+ }
+
+ if (has_errors) {
+ return {};
+ }
+ return {output_artifact};
+}
+
+} // namespace
+
+namespace configuration {
+
+const StringPiece& AbiToString(Abi abi) {
+ return kAbiToStringMap.at(static_cast<size_t>(abi));
+}
+
+/**
* Returns the common artifact base name from a template string.
*/
Maybe<std::string> ToBaseName(std::string result, const StringPiece& apk_name, IDiagnostics* diag) {
@@ -186,8 +362,9 @@
return result;
}
-Maybe<std::string> Artifact::ToArtifactName(const StringPiece& format, const StringPiece& apk_name,
- IDiagnostics* diag) const {
+Maybe<std::string> ConfiguredArtifact::ToArtifactName(const StringPiece& format,
+ const StringPiece& apk_name,
+ IDiagnostics* diag) const {
Maybe<std::string> base = ToBaseName(format.to_string(), apk_name, diag);
if (!base) {
return {};
@@ -221,7 +398,7 @@
return result;
}
-Maybe<std::string> Artifact::Name(const StringPiece& apk_name, IDiagnostics* diag) const {
+Maybe<std::string> ConfiguredArtifact::Name(const StringPiece& apk_name, IDiagnostics* diag) const {
if (!name) {
return {};
}
@@ -229,31 +406,6 @@
return ToBaseName(name.value(), apk_name, diag);
}
-bool PostProcessingConfiguration::AllArtifactNames(const StringPiece& apk_name,
- std::vector<std::string>* artifact_names,
- IDiagnostics* diag) const {
- for (const auto& artifact : artifacts) {
- Maybe<std::string> name;
- if (artifact.name) {
- name = artifact.Name(apk_name, diag);
- } else {
- if (!artifact_format) {
- diag->Error(DiagMessage() << "No global artifact template and an artifact name is missing");
- return false;
- }
- name = artifact.ToArtifactName(artifact_format.value(), apk_name, diag);
- }
-
- if (!name) {
- return false;
- }
-
- artifact_names->push_back(std::move(name.value()));
- }
-
- return true;
-}
-
} // namespace configuration
/** Returns a ConfigurationParser for the file located at the provided path. */
@@ -270,86 +422,58 @@
diag_(&noop_) {
}
-Maybe<PostProcessingConfiguration> ConfigurationParser::Parse() {
- StringInputStream in(contents_);
- std::unique_ptr<xml::XmlResource> doc = xml::Inflate(&in, diag_, Source("config.xml"));
- if (!doc) {
+Maybe<std::vector<OutputArtifact>> ConfigurationParser::Parse(
+ const android::StringPiece& apk_path) {
+ Maybe<PostProcessingConfiguration> maybe_config = ExtractConfiguration(contents_, diag_);
+ if (!maybe_config) {
return {};
}
-
- // Strip any namespaces from the XML as the XmlActionExecutor ignores anything with a namespace.
- Element* root = doc->root.get();
- if (root == nullptr) {
- diag_->Error(DiagMessage() << "Could not find the root element in the XML document");
- return {};
- }
-
- std::string& xml_ns = root->namespace_uri;
- if (!xml_ns.empty()) {
- if (xml_ns != kAaptXmlNs) {
- diag_->Error(DiagMessage() << "Unknown namespace found on root element: " << xml_ns);
- return {};
- }
-
- xml_ns.clear();
- NamespaceVisitor visitor;
- root->Accept(&visitor);
- }
-
- XmlActionExecutor executor;
- XmlNodeAction& root_action = executor["post-process"];
- XmlNodeAction& artifacts_action = root_action["artifacts"];
- XmlNodeAction& groups_action = root_action["groups"];
-
- PostProcessingConfiguration config;
-
- // Helper to bind a static method to an action handler in the DOM executor.
- auto bind_handler =
- [&config](std::function<bool(PostProcessingConfiguration*, Element*, IDiagnostics*)> h)
- -> XmlNodeAction::ActionFuncWithDiag {
- return std::bind(h, &config, std::placeholders::_1, std::placeholders::_2);
- };
-
- // Parse the artifact elements.
- artifacts_action["artifact"].Action(bind_handler(artifact_handler_));
- artifacts_action["artifact-format"].Action(bind_handler(artifact_format_handler_));
-
- // Parse the different configuration groups.
- groups_action["abi-group"].Action(bind_handler(abi_group_handler_));
- groups_action["screen-density-group"].Action(bind_handler(screen_density_group_handler_));
- groups_action["locale-group"].Action(bind_handler(locale_group_handler_));
- groups_action["android-sdk-group"].Action(bind_handler(android_sdk_group_handler_));
- groups_action["gl-texture-group"].Action(bind_handler(gl_texture_group_handler_));
- groups_action["device-feature-group"].Action(bind_handler(device_feature_group_handler_));
-
- if (!executor.Execute(XmlActionExecutorPolicy::kNone, diag_, doc.get())) {
- diag_->Error(DiagMessage() << "Could not process XML document");
- return {};
- }
-
- // TODO: Validate all references in the configuration are valid. It should be safe to assume from
- // this point on that any references from one section to another will be present.
+ const PostProcessingConfiguration& config = maybe_config.value();
// TODO: Automatically arrange artifacts so that they match Play Store multi-APK requirements.
// see: https://developer.android.com/google/play/publishing/multiple-apks.html
//
// For now, make sure the version codes are unique.
- std::vector<Artifact>& artifacts = config.artifacts;
+ std::vector<ConfiguredArtifact> artifacts = config.artifacts;
std::sort(artifacts.begin(), artifacts.end());
if (std::adjacent_find(artifacts.begin(), artifacts.end()) != artifacts.end()) {
diag_->Error(DiagMessage() << "Configuration has duplicate versions");
return {};
}
- return {config};
+ const std::string& apk_name = file::GetFilename(apk_path).to_string();
+ const StringPiece ext = file::GetExtension(apk_name);
+ const std::string base_name = apk_name.substr(0, apk_name.size() - ext.size());
+
+ // Convert from a parsed configuration to a list of artifacts for processing.
+ std::vector<OutputArtifact> output_artifacts;
+ bool has_errors = false;
+
+ for (const ConfiguredArtifact& artifact : artifacts) {
+ Maybe<OutputArtifact> output_artifact = ToOutputArtifact(artifact, apk_name, config, diag_);
+ if (!output_artifact) {
+ // Defer return an error condition so that all errors are reported.
+ has_errors = true;
+ } else {
+ output_artifacts.push_back(std::move(output_artifact.value()));
+ }
+ }
+
+ if (has_errors) {
+ return {};
+ }
+ return {output_artifacts};
}
-ConfigurationParser::ActionHandler ConfigurationParser::artifact_handler_ =
- [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool {
+namespace configuration {
+namespace handler {
+
+bool ArtifactTagHandler(PostProcessingConfiguration* config, Element* root_element,
+ IDiagnostics* diag) {
// This will be incremented later so the first version will always be different to the base APK.
int current_version = (config->artifacts.empty()) ? 0 : config->artifacts.back().version;
- Artifact artifact{};
+ ConfiguredArtifact artifact{};
Maybe<int> version;
for (const auto& attr : root_element->attributes) {
if (attr.name == "name") {
@@ -380,8 +504,8 @@
return true;
};
-ConfigurationParser::ActionHandler ConfigurationParser::artifact_format_handler_ =
- [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool {
+bool ArtifactFormatTagHandler(PostProcessingConfiguration* config, Element* root_element,
+ IDiagnostics* /* diag */) {
for (auto& node : root_element->children) {
xml::Text* t;
if ((t = NodeCast<xml::Text>(node.get())) != nullptr) {
@@ -392,8 +516,8 @@
return true;
};
-ConfigurationParser::ActionHandler ConfigurationParser::abi_group_handler_ =
- [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool {
+bool AbiGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
+ IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -420,8 +544,8 @@
return valid;
};
-ConfigurationParser::ActionHandler ConfigurationParser::screen_density_group_handler_ =
- [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool {
+bool ScreenDensityGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
+ IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -461,8 +585,8 @@
return valid;
};
-ConfigurationParser::ActionHandler ConfigurationParser::locale_group_handler_ =
- [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool {
+bool LocaleGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
+ IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -502,8 +626,8 @@
return valid;
};
-ConfigurationParser::ActionHandler ConfigurationParser::android_sdk_group_handler_ =
- [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool {
+bool AndroidSdkGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
+ IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -519,14 +643,22 @@
} else {
AndroidSdk entry;
for (const auto& attr : child->attributes) {
+ Maybe<int>* target = nullptr;
if (attr.name == "minSdkVersion") {
- entry.min_sdk_version = ResourceUtils::ParseSdkVersion(attr.value);
+ target = &entry.min_sdk_version;
} else if (attr.name == "targetSdkVersion") {
- entry.target_sdk_version = ResourceUtils::ParseSdkVersion(attr.value);
+ target = &entry.target_sdk_version;
} else if (attr.name == "maxSdkVersion") {
- entry.max_sdk_version = ResourceUtils::ParseSdkVersion(attr.value);
+ target = &entry.max_sdk_version;
} else {
diag->Warn(DiagMessage() << "Unknown attribute: " << attr.name << " = " << attr.value);
+ continue;
+ }
+
+ *target = ResourceUtils::ParseSdkVersion(attr.value);
+ if (!*target) {
+ diag->Error(DiagMessage() << "Invalid attribute: " << attr.name << " = " << attr.value);
+ valid = false;
}
}
@@ -552,8 +684,8 @@
return valid;
};
-ConfigurationParser::ActionHandler ConfigurationParser::gl_texture_group_handler_ =
- [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool {
+bool GlTextureGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
+ IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -595,8 +727,8 @@
return valid;
};
-ConfigurationParser::ActionHandler ConfigurationParser::device_feature_group_handler_ =
- [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool {
+bool DeviceFeatureGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
+ IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -624,4 +756,7 @@
return valid;
};
+} // namespace handler
+} // namespace configuration
+
} // namespace aapt
diff --git a/tools/aapt2/configuration/ConfigurationParser.h b/tools/aapt2/configuration/ConfigurationParser.h
index c5d3284..ca58910 100644
--- a/tools/aapt2/configuration/ConfigurationParser.h
+++ b/tools/aapt2/configuration/ConfigurationParser.h
@@ -30,54 +30,6 @@
namespace configuration {
-/** A mapping of group labels to group of configuration items. */
-template<class T>
-using Group = std::unordered_map<std::string, std::vector<T>>;
-
-/** A mapping of group label to a single configuration item. */
-template <class T>
-using Entry = std::unordered_map<std::string, T>;
-
-/** Output artifact configuration options. */
-struct Artifact {
- /** Name to use for output of processing foo.apk -> foo.<name>.apk. */
- Maybe<std::string> name;
- /**
- * Value to add to the base Android manifest versionCode. If it is not present in the
- * configuration file, it is set to the previous artifact + 1. If the first artifact does not have
- * a value, artifacts are a 1 based index.
- */
- int version;
- /** If present, uses the ABI group with this name. */
- Maybe<std::string> abi_group;
- /** If present, uses the screen density group with this name. */
- Maybe<std::string> screen_density_group;
- /** If present, uses the locale group with this name. */
- Maybe<std::string> locale_group;
- /** If present, uses the Android SDK group with this name. */
- Maybe<std::string> android_sdk_group;
- /** If present, uses the device feature group with this name. */
- Maybe<std::string> device_feature_group;
- /** If present, uses the OpenGL texture group with this name. */
- Maybe<std::string> gl_texture_group;
-
- /** Convert an artifact name template into a name string based on configuration contents. */
- Maybe<std::string> ToArtifactName(const android::StringPiece& format,
- const android::StringPiece& apk_name, IDiagnostics* diag) const;
-
- /** Convert an artifact name template into a name string based on configuration contents. */
- Maybe<std::string> Name(const android::StringPiece& apk_name, IDiagnostics* diag) const;
-
- bool operator<(const Artifact& rhs) const {
- // TODO(safarmer): Order by play store multi-APK requirements.
- return version < rhs.version;
- }
-
- bool operator==(const Artifact& rhs) const {
- return version == rhs.version;
- }
-};
-
/** Enumeration of currently supported ABIs. */
enum class Abi {
kArmeV6,
@@ -91,7 +43,7 @@
};
/** Helper method to convert an ABI to a string representing the path within the APK. */
-const std::string& AbiToString(Abi abi);
+const android::StringPiece& AbiToString(Abi abi);
/**
* Represents an individual locale. When a locale is included, it must be
@@ -151,22 +103,16 @@
}
};
-/** AAPT2 XML configuration file binary representation. */
-struct PostProcessingConfiguration {
- // TODO: Support named artifacts?
- std::vector<Artifact> artifacts;
- Maybe<std::string> artifact_format;
-
- Group<Abi> abi_groups;
- Group<ConfigDescription> screen_density_groups;
- Group<ConfigDescription> locale_groups;
- Entry<AndroidSdk> android_sdk_groups;
- Group<DeviceFeature> device_feature_groups;
- Group<GlTexture> gl_texture_groups;
-
- /** Helper method that generates a list of artifact names and returns true on success. */
- bool AllArtifactNames(const android::StringPiece& apk_name,
- std::vector<std::string>* artifact_names, IDiagnostics* diag) const;
+/** An artifact with all the details pulled from the PostProcessingConfiguration. */
+struct OutputArtifact {
+ std::string name;
+ int version;
+ std::vector<Abi> abis;
+ std::vector<ConfigDescription> screen_densities;
+ std::vector<ConfigDescription> locales;
+ Maybe<AndroidSdk> android_sdk;
+ std::vector<DeviceFeature> features;
+ std::vector<GlTexture> textures;
};
} // namespace configuration
@@ -202,7 +148,7 @@
* Parses the configuration file and returns the results. If the configuration could not be parsed
* the result is empty and any errors will be displayed with the provided diagnostics context.
*/
- Maybe<configuration::PostProcessingConfiguration> Parse();
+ Maybe<std::vector<configuration::OutputArtifact>> Parse(const android::StringPiece& apk_path);
protected:
/**
@@ -217,30 +163,6 @@
return diag_;
}
- /**
- * An ActionHandler for processing XML elements in the XmlActionExecutor. Returns true if the
- * element was successfully processed, otherwise returns false.
- */
- using ActionHandler = std::function<bool(configuration::PostProcessingConfiguration* config,
- xml::Element* element, IDiagnostics* diag)>;
-
- /** Handler for <artifact> tags. */
- static ActionHandler artifact_handler_;
- /** Handler for <artifact-format> tags. */
- static ActionHandler artifact_format_handler_;
- /** Handler for <abi-group> tags. */
- static ActionHandler abi_group_handler_;
- /** Handler for <screen-density-group> tags. */
- static ActionHandler screen_density_group_handler_;
- /** Handler for <locale-group> tags. */
- static ActionHandler locale_group_handler_;
- /** Handler for <android-sdk-group> tags. */
- static ActionHandler android_sdk_group_handler_;
- /** Handler for <gl-texture-group> tags. */
- static ActionHandler gl_texture_group_handler_;
- /** Handler for <device-feature-group> tags. */
- static ActionHandler device_feature_group_handler_;
-
private:
/** The contents of the configuration file to parse. */
const std::string contents_;
diff --git a/tools/aapt2/configuration/ConfigurationParser.internal.h b/tools/aapt2/configuration/ConfigurationParser.internal.h
new file mode 100644
index 0000000..7657ebd
--- /dev/null
+++ b/tools/aapt2/configuration/ConfigurationParser.internal.h
@@ -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.
+ */
+
+#ifndef AAPT2_CONFIGURATIONPARSER_INTERNAL_H
+#define AAPT2_CONFIGURATIONPARSER_INTERNAL_H
+
+namespace aapt {
+namespace configuration {
+
+/** A mapping of group labels to group of configuration items. */
+template <class T>
+using Group = std::unordered_map<std::string, std::vector<T>>;
+
+/** A mapping of group label to a single configuration item. */
+template <class T>
+using Entry = std::unordered_map<std::string, T>;
+
+/** Output artifact configuration options. */
+struct ConfiguredArtifact {
+ /** Name to use for output of processing foo.apk -> foo.<name>.apk. */
+ Maybe<std::string> name;
+ /**
+ * Value to add to the base Android manifest versionCode. If it is not present in the
+ * configuration file, it is set to the previous artifact + 1. If the first artifact does not have
+ * a value, artifacts are a 1 based index.
+ */
+ int version;
+ /** If present, uses the ABI group with this name. */
+ Maybe<std::string> abi_group;
+ /** If present, uses the screen density group with this name. */
+ Maybe<std::string> screen_density_group;
+ /** If present, uses the locale group with this name. */
+ Maybe<std::string> locale_group;
+ /** If present, uses the Android SDK group with this name. */
+ Maybe<std::string> android_sdk_group;
+ /** If present, uses the device feature group with this name. */
+ Maybe<std::string> device_feature_group;
+ /** If present, uses the OpenGL texture group with this name. */
+ Maybe<std::string> gl_texture_group;
+
+ /** Convert an artifact name template into a name string based on configuration contents. */
+ Maybe<std::string> ToArtifactName(const android::StringPiece& format,
+ const android::StringPiece& apk_name, IDiagnostics* diag) const;
+
+ /** Convert an artifact name template into a name string based on configuration contents. */
+ Maybe<std::string> Name(const android::StringPiece& apk_name, IDiagnostics* diag) const;
+
+ bool operator<(const ConfiguredArtifact& rhs) const {
+ // TODO(safarmer): Order by play store multi-APK requirements.
+ return version < rhs.version;
+ }
+
+ bool operator==(const ConfiguredArtifact& rhs) const {
+ return version == rhs.version;
+ }
+};
+
+/** AAPT2 XML configuration file binary representation. */
+struct PostProcessingConfiguration {
+ // TODO: Support named artifacts?
+ std::vector<ConfiguredArtifact> artifacts;
+ Maybe<std::string> artifact_format;
+
+ Group<Abi> abi_groups;
+ Group<ConfigDescription> screen_density_groups;
+ Group<ConfigDescription> locale_groups;
+ Entry<AndroidSdk> android_sdk_groups;
+ Group<DeviceFeature> device_feature_groups;
+ Group<GlTexture> gl_texture_groups;
+};
+
+namespace handler {
+
+/** Handler for <artifact> tags. */
+bool ArtifactTagHandler(configuration::PostProcessingConfiguration* config, xml::Element* element,
+ IDiagnostics* diag);
+
+/** Handler for <artifact-format> tags. */
+bool ArtifactFormatTagHandler(configuration::PostProcessingConfiguration* config,
+ xml::Element* element, IDiagnostics* diag);
+
+/** Handler for <abi-group> tags. */
+bool AbiGroupTagHandler(configuration::PostProcessingConfiguration* config, xml::Element* element,
+ IDiagnostics* diag);
+
+/** Handler for <screen-density-group> tags. */
+bool ScreenDensityGroupTagHandler(configuration::PostProcessingConfiguration* config,
+ xml::Element* element, IDiagnostics* diag);
+
+/** Handler for <locale-group> tags. */
+bool LocaleGroupTagHandler(configuration::PostProcessingConfiguration* config,
+ xml::Element* element, IDiagnostics* diag);
+
+/** Handler for <android-sdk-group> tags. */
+bool AndroidSdkGroupTagHandler(configuration::PostProcessingConfiguration* config,
+ xml::Element* element, IDiagnostics* diag);
+
+/** Handler for <gl-texture-group> tags. */
+bool GlTextureGroupTagHandler(configuration::PostProcessingConfiguration* config,
+ xml::Element* element, IDiagnostics* diag);
+
+/** Handler for <device-feature-group> tags. */
+bool DeviceFeatureGroupTagHandler(configuration::PostProcessingConfiguration* config,
+ xml::Element* element, IDiagnostics* diag);
+
+} // namespace handler
+} // namespace configuration
+} // namespace aapt
+#endif // AAPT2_CONFIGURATIONPARSER_INTERNAL_H
diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp
index afa155f..3f356d7 100644
--- a/tools/aapt2/configuration/ConfigurationParser_test.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp
@@ -18,8 +18,11 @@
#include <string>
+#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
+#include "SdkConstants.h"
+#include "configuration/ConfigurationParser.internal.h"
#include "test/Test.h"
#include "xml/XmlDom.h"
@@ -31,22 +34,25 @@
<< ", target=" << sdk.target_sdk_version.value_or_default(-1)
<< ", max=" << sdk.max_sdk_version.value_or_default(-1);
}
-} // namespace configuration
+
+namespace handler {
namespace {
+using ::aapt::configuration::Abi;
+using ::aapt::configuration::AndroidManifest;
+using ::aapt::configuration::AndroidSdk;
+using ::aapt::configuration::ConfiguredArtifact;
+using ::aapt::configuration::DeviceFeature;
+using ::aapt::configuration::GlTexture;
+using ::aapt::configuration::Locale;
+using ::aapt::configuration::PostProcessingConfiguration;
+using ::aapt::xml::Element;
+using ::aapt::xml::NodeCast;
using ::android::ResTable_config;
-using configuration::Abi;
-using configuration::AndroidSdk;
-using configuration::Artifact;
-using configuration::PostProcessingConfiguration;
-using configuration::DeviceFeature;
-using configuration::GlTexture;
-using configuration::Locale;
-using configuration::AndroidManifest;
+using ::android::base::StringPrintf;
using ::testing::ElementsAre;
-using xml::Element;
-using xml::NodeCast;
+using ::testing::SizeIs;
constexpr const char* kValidConfig = R"(<?xml version="1.0" encoding="utf-8" ?>
<post-process xmlns="http://schemas.android.com/tools/aapt">
@@ -141,44 +147,47 @@
TEST_F(ConfigurationParserTest, ValidateFile) {
auto parser = ConfigurationParser::ForContents(kValidConfig).WithDiagnostics(&diag_);
- auto result = parser.Parse();
+ auto result = parser.Parse("test.apk");
ASSERT_TRUE(result);
- PostProcessingConfiguration& value = result.value();
- EXPECT_EQ(2ul, value.artifacts.size());
- ASSERT_TRUE(value.artifact_format);
- EXPECT_EQ(
- "${base}.${abi}.${screen-density}.${locale}.${sdk}.${gl}.${feature}.release",
- value.artifact_format.value()
- );
+ const std::vector<OutputArtifact>& value = result.value();
+ EXPECT_THAT(value, SizeIs(2ul));
- EXPECT_EQ(2ul, value.abi_groups.size());
- EXPECT_EQ(2ul, value.abi_groups["arm"].size());
- EXPECT_EQ(2ul, value.abi_groups["other"].size());
+ const OutputArtifact& a1 = value[0];
+ EXPECT_EQ(a1.name, "art1.apk");
+ EXPECT_THAT(a1.abis, ElementsAre(Abi::kArmV7a, Abi::kArm64V8a));
+ EXPECT_THAT(a1.screen_densities,
+ ElementsAre(test::ParseConfigOrDie("xhdpi").CopyWithoutSdkVersion(),
+ test::ParseConfigOrDie("xxhdpi").CopyWithoutSdkVersion(),
+ test::ParseConfigOrDie("xxxhdpi").CopyWithoutSdkVersion()));
+ EXPECT_THAT(a1.locales, ElementsAre(test::ParseConfigOrDie("en"), test::ParseConfigOrDie("es"),
+ test::ParseConfigOrDie("fr"), test::ParseConfigOrDie("de")));
+ EXPECT_EQ(a1.android_sdk.value().min_sdk_version.value(), 19l);
+ EXPECT_THAT(a1.textures, SizeIs(1ul));
+ EXPECT_THAT(a1.features, SizeIs(1ul));
- EXPECT_EQ(2ul, value.screen_density_groups.size());
- EXPECT_EQ(3ul, value.screen_density_groups["large"].size());
- EXPECT_EQ(6ul, value.screen_density_groups["alldpi"].size());
-
- EXPECT_EQ(2ul, value.locale_groups.size());
- EXPECT_EQ(4ul, value.locale_groups["europe"].size());
- EXPECT_EQ(3ul, value.locale_groups["north-america"].size());
-
- EXPECT_EQ(1ul, value.android_sdk_groups.size());
- EXPECT_TRUE(value.android_sdk_groups["v19"].min_sdk_version);
- EXPECT_EQ(19, value.android_sdk_groups["v19"].min_sdk_version.value());
-
- EXPECT_EQ(1ul, value.gl_texture_groups.size());
- EXPECT_EQ(1ul, value.gl_texture_groups["dxt1"].size());
-
- EXPECT_EQ(1ul, value.device_feature_groups.size());
- EXPECT_EQ(1ul, value.device_feature_groups["low-latency"].size());
+ const OutputArtifact& a2 = value[1];
+ EXPECT_EQ(a2.name, "art2.apk");
+ EXPECT_THAT(a2.abis, ElementsAre(Abi::kX86, Abi::kMips));
+ EXPECT_THAT(a2.screen_densities,
+ ElementsAre(test::ParseConfigOrDie("ldpi").CopyWithoutSdkVersion(),
+ test::ParseConfigOrDie("mdpi").CopyWithoutSdkVersion(),
+ test::ParseConfigOrDie("hdpi").CopyWithoutSdkVersion(),
+ test::ParseConfigOrDie("xhdpi").CopyWithoutSdkVersion(),
+ test::ParseConfigOrDie("xxhdpi").CopyWithoutSdkVersion(),
+ test::ParseConfigOrDie("xxxhdpi").CopyWithoutSdkVersion()));
+ EXPECT_THAT(a2.locales,
+ ElementsAre(test::ParseConfigOrDie("en"), test::ParseConfigOrDie("es-rMX"),
+ test::ParseConfigOrDie("fr-rCA")));
+ EXPECT_EQ(a2.android_sdk.value().min_sdk_version.value(), 19l);
+ EXPECT_THAT(a2.textures, SizeIs(1ul));
+ EXPECT_THAT(a2.features, SizeIs(1ul));
}
TEST_F(ConfigurationParserTest, InvalidNamespace) {
constexpr const char* invalid_ns = R"(<?xml version="1.0" encoding="utf-8" ?>
<post-process xmlns="http://schemas.android.com/tools/another-unknown-tool" />)";
- auto result = ConfigurationParser::ForContents(invalid_ns).Parse();
+ auto result = ConfigurationParser::ForContents(invalid_ns).Parse("test.apk");
ASSERT_FALSE(result);
}
@@ -194,9 +203,9 @@
gl-texture-group="dxt1"
device-feature-group="low-latency"/>)xml");
- ASSERT_TRUE(artifact_handler_(&config, NodeCast<Element>(doc->root.get()), &diag_));
+ ASSERT_TRUE(ArtifactTagHandler(&config, NodeCast<Element>(doc->root.get()), &diag_));
- EXPECT_EQ(1ul, config.artifacts.size());
+ EXPECT_THAT(config.artifacts, SizeIs(1ul));
auto& artifact = config.artifacts.back();
EXPECT_FALSE(artifact.name); // TODO: make this fail.
@@ -220,8 +229,8 @@
gl-texture-group="dxt1"
device-feature-group="low-latency"/>)xml");
- ASSERT_TRUE(artifact_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_));
- EXPECT_EQ(2ul, config.artifacts.size());
+ ASSERT_TRUE(ArtifactTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_));
+ EXPECT_THAT(config.artifacts, SizeIs(2ul));
EXPECT_EQ(2, config.artifacts.back().version);
}
@@ -237,8 +246,8 @@
gl-texture-group="dxt1"
device-feature-group="low-latency"/>)xml");
- ASSERT_TRUE(artifact_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_));
- EXPECT_EQ(3ul, config.artifacts.size());
+ ASSERT_TRUE(ArtifactTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_));
+ EXPECT_THAT(config.artifacts, SizeIs(3ul));
EXPECT_EQ(5, config.artifacts.back().version);
}
@@ -253,8 +262,8 @@
gl-texture-group="dxt1"
device-feature-group="low-latency"/>)xml");
- ASSERT_TRUE(artifact_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_));
- EXPECT_EQ(4ul, config.artifacts.size());
+ ASSERT_TRUE(ArtifactTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_));
+ EXPECT_THAT(config.artifacts, SizeIs(4ul));
EXPECT_EQ(6, config.artifacts.back().version);
}
}
@@ -285,7 +294,7 @@
device-feature-group="low-latency"/>
</artifacts>
</post-process>)xml";
- auto result = ConfigurationParser::ForContents(configuration).Parse();
+ auto result = ConfigurationParser::ForContents(configuration).Parse("test.apk");
ASSERT_FALSE(result);
}
@@ -296,7 +305,7 @@
</artifact-format>)xml");
PostProcessingConfiguration config;
- bool ok = artifact_format_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ bool ok = ArtifactFormatTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
ASSERT_TRUE(ok);
ASSERT_TRUE(config.artifact_format);
EXPECT_EQ(
@@ -319,10 +328,10 @@
auto doc = test::BuildXmlDom(xml);
PostProcessingConfiguration config;
- bool ok = abi_group_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ bool ok = AbiGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
ASSERT_TRUE(ok);
- EXPECT_EQ(1ul, config.abi_groups.size());
+ EXPECT_THAT(config.abi_groups, SizeIs(1ul));
ASSERT_EQ(1u, config.abi_groups.count("arm"));
auto& out = config.abi_groups["arm"];
@@ -342,11 +351,10 @@
auto doc = test::BuildXmlDom(xml);
PostProcessingConfiguration config;
- bool ok =
- screen_density_group_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ bool ok = ScreenDensityGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
ASSERT_TRUE(ok);
- EXPECT_EQ(1ul, config.screen_density_groups.size());
+ EXPECT_THAT(config.screen_density_groups, SizeIs(1ul));
ASSERT_EQ(1u, config.screen_density_groups.count("large"));
ConfigDescription xhdpi;
@@ -372,7 +380,7 @@
auto doc = test::BuildXmlDom(xml);
PostProcessingConfiguration config;
- bool ok = locale_group_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ bool ok = LocaleGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
ASSERT_TRUE(ok);
ASSERT_EQ(1ul, config.locale_groups.size());
@@ -404,7 +412,7 @@
auto doc = test::BuildXmlDom(xml);
PostProcessingConfiguration config;
- bool ok = android_sdk_group_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ bool ok = AndroidSdkGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
ASSERT_TRUE(ok);
ASSERT_EQ(1ul, config.android_sdk_groups.size());
@@ -421,20 +429,109 @@
ASSERT_EQ(sdk, out);
}
-TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_NonNumeric) {
+TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_SingleVersion) {
+ {
+ static constexpr const char* xml = R"xml(
+ <android-sdk-group label="v19">
+ <android-sdk minSdkVersion="19"></android-sdk>
+ </android-sdk-group>)xml";
+
+ auto doc = test::BuildXmlDom(xml);
+
+ PostProcessingConfiguration config;
+ bool ok = AndroidSdkGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ ASSERT_TRUE(ok);
+
+ ASSERT_EQ(1ul, config.android_sdk_groups.size());
+ ASSERT_EQ(1u, config.android_sdk_groups.count("v19"));
+
+ auto& out = config.android_sdk_groups["v19"];
+ EXPECT_EQ(19, out.min_sdk_version.value());
+ EXPECT_FALSE(out.max_sdk_version);
+ EXPECT_FALSE(out.target_sdk_version);
+ }
+
+ {
+ static constexpr const char* xml = R"xml(
+ <android-sdk-group label="v19">
+ <android-sdk maxSdkVersion="19"></android-sdk>
+ </android-sdk-group>)xml";
+
+ auto doc = test::BuildXmlDom(xml);
+
+ PostProcessingConfiguration config;
+ bool ok = AndroidSdkGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ ASSERT_TRUE(ok);
+
+ ASSERT_EQ(1ul, config.android_sdk_groups.size());
+ ASSERT_EQ(1u, config.android_sdk_groups.count("v19"));
+
+ auto& out = config.android_sdk_groups["v19"];
+ EXPECT_EQ(19, out.max_sdk_version.value());
+ EXPECT_FALSE(out.min_sdk_version);
+ EXPECT_FALSE(out.target_sdk_version);
+ }
+
+ {
+ static constexpr const char* xml = R"xml(
+ <android-sdk-group label="v19">
+ <android-sdk targetSdkVersion="19"></android-sdk>
+ </android-sdk-group>)xml";
+
+ auto doc = test::BuildXmlDom(xml);
+
+ PostProcessingConfiguration config;
+ bool ok = AndroidSdkGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ ASSERT_TRUE(ok);
+
+ ASSERT_EQ(1ul, config.android_sdk_groups.size());
+ ASSERT_EQ(1u, config.android_sdk_groups.count("v19"));
+
+ auto& out = config.android_sdk_groups["v19"];
+ EXPECT_EQ(19, out.target_sdk_version.value());
+ EXPECT_FALSE(out.min_sdk_version);
+ EXPECT_FALSE(out.max_sdk_version);
+ }
+}
+
+TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_InvalidVersion) {
static constexpr const char* xml = R"xml(
- <android-sdk-group label="P">
+ <android-sdk-group label="v19">
<android-sdk
- minSdkVersion="M"
- targetSdkVersion="P"
- maxSdkVersion="P">
+ minSdkVersion="v19"
+ targetSdkVersion="v24"
+ maxSdkVersion="v25">
+ <manifest>
+ <!--- manifest additions here XSLT? TODO -->
+ </manifest>
</android-sdk>
</android-sdk-group>)xml";
auto doc = test::BuildXmlDom(xml);
PostProcessingConfiguration config;
- bool ok = android_sdk_group_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ bool ok = AndroidSdkGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ ASSERT_FALSE(ok);
+}
+
+TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_NonNumeric) {
+ static constexpr const char* xml = R"xml(
+ <android-sdk-group label="P">
+ <android-sdk
+ minSdkVersion="25"
+ targetSdkVersion="%s"
+ maxSdkVersion="%s">
+ </android-sdk>
+ </android-sdk-group>)xml";
+
+ const auto& dev_sdk = GetDevelopmentSdkCodeNameAndVersion();
+ const char* codename = dev_sdk.first.data();
+ const ApiVersion& version = dev_sdk.second;
+
+ auto doc = test::BuildXmlDom(StringPrintf(xml, codename, codename));
+
+ PostProcessingConfiguration config;
+ bool ok = AndroidSdkGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
ASSERT_TRUE(ok);
ASSERT_EQ(1ul, config.android_sdk_groups.size());
@@ -443,9 +540,9 @@
auto& out = config.android_sdk_groups["P"];
AndroidSdk sdk;
- sdk.min_sdk_version = {}; // Only the latest development version is supported.
- sdk.target_sdk_version = 28;
- sdk.max_sdk_version = 28;
+ sdk.min_sdk_version = 25;
+ sdk.target_sdk_version = version;
+ sdk.max_sdk_version = version;
ASSERT_EQ(sdk, out);
}
@@ -464,10 +561,10 @@
auto doc = test::BuildXmlDom(xml);
PostProcessingConfiguration config;
- bool ok = gl_texture_group_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ bool ok = GlTextureGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
ASSERT_TRUE(ok);
- EXPECT_EQ(1ul, config.gl_texture_groups.size());
+ EXPECT_THAT(config.gl_texture_groups, SizeIs(1ul));
ASSERT_EQ(1u, config.gl_texture_groups.count("dxt1"));
auto& out = config.gl_texture_groups["dxt1"];
@@ -493,11 +590,10 @@
auto doc = test::BuildXmlDom(xml);
PostProcessingConfiguration config;
- bool ok
- = device_feature_group_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ bool ok = DeviceFeatureGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
ASSERT_TRUE(ok);
- EXPECT_EQ(1ul, config.device_feature_groups.size());
+ EXPECT_THAT(config.device_feature_groups, SizeIs(1ul));
ASSERT_EQ(1u, config.device_feature_groups.count("low-latency"));
auto& out = config.device_feature_groups["low-latency"];
@@ -511,14 +607,14 @@
TEST(ArtifactTest, Simple) {
StdErrDiagnostics diag;
- Artifact x86;
+ ConfiguredArtifact x86;
x86.abi_group = {"x86"};
auto x86_result = x86.ToArtifactName("something.${abi}.apk", "", &diag);
ASSERT_TRUE(x86_result);
EXPECT_EQ(x86_result.value(), "something.x86.apk");
- Artifact arm;
+ ConfiguredArtifact arm;
arm.abi_group = {"armeabi-v7a"};
{
@@ -548,7 +644,7 @@
TEST(ArtifactTest, Complex) {
StdErrDiagnostics diag;
- Artifact artifact;
+ ConfiguredArtifact artifact;
artifact.abi_group = {"mips64"};
artifact.screen_density_group = {"ldpi"};
artifact.device_feature_group = {"df1"};
@@ -594,7 +690,7 @@
TEST(ArtifactTest, Missing) {
StdErrDiagnostics diag;
- Artifact x86;
+ ConfiguredArtifact x86;
x86.abi_group = {"x86"};
EXPECT_FALSE(x86.ToArtifactName("something.${density}.apk", "", &diag));
@@ -605,7 +701,7 @@
TEST(ArtifactTest, Empty) {
StdErrDiagnostics diag;
- Artifact artifact;
+ ConfiguredArtifact artifact;
EXPECT_FALSE(artifact.ToArtifactName("something.${density}.apk", "", &diag));
EXPECT_TRUE(artifact.ToArtifactName("something.apk", "", &diag));
@@ -615,7 +711,7 @@
TEST(ArtifactTest, Repeated) {
StdErrDiagnostics diag;
- Artifact artifact;
+ ConfiguredArtifact artifact;
artifact.screen_density_group = {"mdpi"};
ASSERT_TRUE(artifact.ToArtifactName("something.${density}.apk", "", &diag));
@@ -625,7 +721,7 @@
TEST(ArtifactTest, Nesting) {
StdErrDiagnostics diag;
- Artifact x86;
+ ConfiguredArtifact x86;
x86.abi_group = {"x86"};
EXPECT_FALSE(x86.ToArtifactName("something.${abi${density}}.apk", "", &diag));
@@ -637,7 +733,7 @@
TEST(ArtifactTest, Recursive) {
StdErrDiagnostics diag;
- Artifact artifact;
+ ConfiguredArtifact artifact;
artifact.device_feature_group = {"${gl}"};
artifact.gl_texture_group = {"glx1"};
@@ -663,4 +759,6 @@
}
} // namespace
+} // namespace handler
+} // namespace configuration
} // namespace aapt
diff --git a/tools/aapt2/filter/AbiFilter.cpp b/tools/aapt2/filter/AbiFilter.cpp
index cb96235..9ace82a 100644
--- a/tools/aapt2/filter/AbiFilter.cpp
+++ b/tools/aapt2/filter/AbiFilter.cpp
@@ -25,7 +25,7 @@
std::unique_ptr<AbiFilter> AbiFilter::FromAbiList(const std::vector<configuration::Abi>& abi_list) {
std::unordered_set<std::string> abi_set;
for (auto& abi : abi_list) {
- abi_set.insert(configuration::AbiToString(abi));
+ abi_set.insert(configuration::AbiToString(abi).to_string());
}
// Make unique by hand as the constructor is private.
return std::unique_ptr<AbiFilter>(new AbiFilter(abi_set));
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/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 9861770..8c8c254 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -272,7 +272,7 @@
// Build the JavaDoc comment for the Styleable array. This has references to child attributes
// and what possible values can be used for them.
const size_t attr_count = sorted_attributes.size();
- if (attr_count > 0) {
+ if (out_class_def != nullptr && attr_count > 0) {
std::stringstream styleable_comment;
if (!styleable.GetComment().empty()) {
styleable_comment << styleable.GetComment() << "\n";
@@ -356,54 +356,56 @@
continue;
}
- StringPiece comment = styleable_attr.attr_ref->GetComment();
- if (styleable_attr.symbol.value().attribute && comment.empty()) {
- comment = styleable_attr.symbol.value().attribute->GetComment();
+ if (out_class_def != nullptr) {
+ StringPiece comment = styleable_attr.attr_ref->GetComment();
+ if (styleable_attr.symbol.value().attribute && comment.empty()) {
+ comment = styleable_attr.symbol.value().attribute->GetComment();
+ }
+
+ if (comment.contains("@removed")) {
+ // Removed attributes are public but hidden from the documentation, so
+ // don't emit them as part of the class documentation.
+ continue;
+ }
+
+ const ResourceName& attr_name = styleable_attr.attr_ref->name.value();
+
+ StringPiece package_name = attr_name.package;
+ if (package_name.empty()) {
+ package_name = context_->GetCompilationPackage();
+ }
+
+ std::unique_ptr<IntMember> index_member =
+ util::make_unique<IntMember>(sorted_attributes[i].field_name, static_cast<uint32_t>(i));
+
+ AnnotationProcessor* attr_processor = index_member->GetCommentBuilder();
+
+ if (!comment.empty()) {
+ attr_processor->AppendComment("<p>\n@attr description");
+ attr_processor->AppendComment(comment);
+ } else {
+ std::stringstream default_comment;
+ default_comment << "<p>This symbol is the offset where the "
+ << "{@link " << package_name << ".R.attr#"
+ << TransformToFieldName(attr_name.entry) << "}\n"
+ << "attribute's value can be found in the "
+ << "{@link #" << array_field_name << "} array.";
+ attr_processor->AppendComment(default_comment.str());
+ }
+
+ attr_processor->AppendNewLine();
+ AddAttributeFormatDoc(attr_processor, styleable_attr.symbol.value().attribute.get());
+ attr_processor->AppendNewLine();
+ attr_processor->AppendComment(
+ StringPrintf("@attr name %s:%s", package_name.data(), attr_name.entry.data()));
+
+ out_class_def->AddMember(std::move(index_member));
}
- if (comment.contains("@removed")) {
- // Removed attributes are public but hidden from the documentation, so
- // don't emit them as part of the class documentation.
- continue;
- }
-
- const ResourceName& attr_name = styleable_attr.attr_ref->name.value();
-
- StringPiece package_name = attr_name.package;
- if (package_name.empty()) {
- package_name = context_->GetCompilationPackage();
- }
-
- std::unique_ptr<IntMember> index_member = util::make_unique<IntMember>(
- sorted_attributes[i].field_name, static_cast<uint32_t>(i));
-
- AnnotationProcessor* attr_processor = index_member->GetCommentBuilder();
-
- if (!comment.empty()) {
- attr_processor->AppendComment("<p>\n@attr description");
- attr_processor->AppendComment(comment);
- } else {
- std::stringstream default_comment;
- default_comment << "<p>This symbol is the offset where the "
- << "{@link " << package_name << ".R.attr#"
- << TransformToFieldName(attr_name.entry) << "}\n"
- << "attribute's value can be found in the "
- << "{@link #" << array_field_name << "} array.";
- attr_processor->AppendComment(default_comment.str());
- }
-
- attr_processor->AppendNewLine();
- AddAttributeFormatDoc(attr_processor, styleable_attr.symbol.value().attribute.get());
- attr_processor->AppendNewLine();
- attr_processor->AppendComment(
- StringPrintf("@attr name %s:%s", package_name.data(), attr_name.entry.data()));
-
if (r_txt_printer != nullptr) {
r_txt_printer->Println(
StringPrintf("int styleable %s %zd", sorted_attributes[i].field_name.c_str(), i));
}
-
- out_class_def->AddMember(std::move(index_member));
}
// If there is a rewrite method to generate, add the statements that rewrite package IDs
@@ -434,31 +436,33 @@
}
const std::string field_name = TransformToFieldName(name.entry);
- std::unique_ptr<ResourceMember> resource_member =
- util::make_unique<ResourceMember>(field_name, real_id);
+ if (out_class_def != nullptr) {
+ std::unique_ptr<ResourceMember> resource_member =
+ util::make_unique<ResourceMember>(field_name, real_id);
- // Build the comments and annotations for this entry.
- AnnotationProcessor* processor = resource_member->GetCommentBuilder();
+ // Build the comments and annotations for this entry.
+ AnnotationProcessor* processor = resource_member->GetCommentBuilder();
- // Add the comments from any <public> tags.
- if (entry.symbol_status.state != SymbolState::kUndefined) {
- processor->AppendComment(entry.symbol_status.comment);
- }
-
- // Add the comments from all configurations of this entry.
- for (const auto& config_value : entry.values) {
- processor->AppendComment(config_value->value->GetComment());
- }
-
- // If this is an Attribute, append the format Javadoc.
- if (!entry.values.empty()) {
- if (Attribute* attr = ValueCast<Attribute>(entry.values.front()->value.get())) {
- // We list out the available values for the given attribute.
- AddAttributeFormatDoc(processor, attr);
+ // Add the comments from any <public> tags.
+ if (entry.symbol_status.state != SymbolState::kUndefined) {
+ processor->AppendComment(entry.symbol_status.comment);
}
- }
- out_class_def->AddMember(std::move(resource_member));
+ // Add the comments from all configurations of this entry.
+ for (const auto& config_value : entry.values) {
+ processor->AppendComment(config_value->value->GetComment());
+ }
+
+ // If this is an Attribute, append the format Javadoc.
+ if (!entry.values.empty()) {
+ if (Attribute* attr = ValueCast<Attribute>(entry.values.front()->value.get())) {
+ // We list out the available values for the given attribute.
+ AddAttributeFormatDoc(processor, attr);
+ }
+ }
+
+ out_class_def->AddMember(std::move(resource_member));
+ }
if (r_txt_printer != nullptr) {
r_txt_printer->Print("int ")
@@ -576,7 +580,7 @@
}
// Generate an onResourcesLoaded() callback if requested.
- if (options_.rewrite_callback_options) {
+ if (out != nullptr && options_.rewrite_callback_options) {
rewrite_method =
util::make_unique<MethodDefinition>("public static void onResourcesLoaded(int p)");
for (const std::string& package_to_callback :
@@ -597,8 +601,12 @@
const bool force_creation_if_empty =
(options_.types == JavaClassGeneratorOptions::SymbolTypes::kPublic);
- std::unique_ptr<ClassDefinition> class_def = util::make_unique<ClassDefinition>(
- to_string(type->type), ClassQualifier::kStatic, force_creation_if_empty);
+ std::unique_ptr<ClassDefinition> class_def;
+ if (out != nullptr) {
+ class_def = util::make_unique<ClassDefinition>(
+ to_string(type->type), ClassQualifier::kStatic, force_creation_if_empty);
+ }
+
if (!ProcessType(package_name_to_generate, *package, *type, class_def.get(),
rewrite_method.get(), r_txt_printer.get())) {
return false;
@@ -615,16 +623,17 @@
}
}
- if (type->type == ResourceType::kStyleable &&
+ if (out != nullptr && type->type == ResourceType::kStyleable &&
options_.types == JavaClassGeneratorOptions::SymbolTypes::kPublic) {
// When generating a public R class, we don't want Styleable to be part
// of the API. It is only emitted for documentation purposes.
class_def->GetCommentBuilder()->AppendComment("@doconly");
}
- AppendJavaDocAnnotations(options_.javadoc_annotations, class_def->GetCommentBuilder());
-
- r_class.AddMember(std::move(class_def));
+ if (out != nullptr) {
+ AppendJavaDocAnnotations(options_.javadoc_annotations, class_def->GetCommentBuilder());
+ r_class.AddMember(std::move(class_def));
+ }
}
}
@@ -632,8 +641,10 @@
r_class.AddMember(std::move(rewrite_method));
}
- AppendJavaDocAnnotations(options_.javadoc_annotations, r_class.GetCommentBuilder());
- ClassDefinition::WriteJavaFile(&r_class, out_package_name, options_.use_final, out);
+ if (out != nullptr) {
+ AppendJavaDocAnnotations(options_.javadoc_annotations, r_class.GetCommentBuilder());
+ ClassDefinition::WriteJavaFile(&r_class, out_package_name, options_.use_final, out);
+ }
return true;
}
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..16898d6 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -17,6 +17,7 @@
#include "MultiApkGenerator.h"
#include <algorithm>
+#include <regex>
#include <string>
#include "androidfw/StringPiece.h"
@@ -39,33 +40,11 @@
namespace aapt {
using ::aapt::configuration::AndroidSdk;
-using ::aapt::configuration::Artifact;
-using ::aapt::configuration::PostProcessingConfiguration;
+using ::aapt::configuration::OutputArtifact;
using ::aapt::xml::kSchemaAndroid;
using ::aapt::xml::XmlResource;
using ::android::StringPiece;
-namespace {
-
-Maybe<AndroidSdk> GetAndroidSdk(const Artifact& artifact, const PostProcessingConfiguration& config,
- IDiagnostics* diag) {
- if (!artifact.android_sdk_group) {
- return {};
- }
-
- const std::string& group_name = artifact.android_sdk_group.value();
- auto group = config.android_sdk_groups.find(group_name);
- // TODO: Remove validation when configuration parser ensures referential integrity.
- if (group == config.android_sdk_groups.end()) {
- diag->Error(DiagMessage() << "could not find referenced group '" << group_name << "'");
- return {};
- }
-
- return group->second;
-}
-
-} // namespace
-
/**
* Context wrapper that allows the min Android SDK value to be overridden.
*/
@@ -84,6 +63,9 @@
}
IDiagnostics* GetDiagnostics() override {
+ if (source_diag_) {
+ return source_diag_.get();
+ }
return context_->GetDiagnostics();
}
@@ -111,148 +93,159 @@
min_sdk_ = min_sdk;
}
+ void SetSource(const std::string& source) {
+ source_diag_ =
+ util::make_unique<SourcePathDiagnostics>(Source{source}, context_->GetDiagnostics());
+ }
+
private:
IAaptContext* context_;
+ std::unique_ptr<SourcePathDiagnostics> source_diag_;
int min_sdk_ = -1;
};
+class SignatureFilter : public IPathFilter {
+ bool Keep(const std::string& path) override {
+ static std::regex signature_regex(R"regex(^META-INF/.*\.(RSA|DSA|EC|SF)$)regex");
+ if (std::regex_search(path, signature_regex)) {
+ return false;
+ }
+ return !(path == "META-INF/MANIFEST.MF");
+ }
+};
+
MultiApkGenerator::MultiApkGenerator(LoadedApk* apk, IAaptContext* context)
: apk_(apk), context_(context) {
}
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) {
+ for (const OutputArtifact& artifact : options.apk_artifacts) {
FilterChain filters;
- if (!artifact.name && !config.artifact_format) {
- diag->Error(
- DiagMessage() << "Artifact does not have a name and no global name template defined");
- return false;
- }
+ ContextWrapper wrapped_context{context_};
+ wrapped_context.SetSource(artifact.name);
- Maybe<std::string> 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");
- return false;
+ 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(context_, artifact, *apk_->GetResourceTable(), &filters);
if (!table) {
return false;
}
+ IDiagnostics* diag = wrapped_context.GetDiagnostics();
+
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, &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);
}
- if (!apk_->WriteToArchive(context_, table.get(), options.table_flattener_options, &filters,
- writer.get(), manifest.get())) {
+ filters.AddFilter(util::make_unique<SignatureFilter>());
+ 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) {
+std::unique_ptr<ResourceTable> MultiApkGenerator::FilterTable(IAaptContext* context,
+ const OutputArtifact& artifact,
+ const ResourceTable& old_table,
+ FilterChain* filters) {
TableSplitterOptions splits;
AxisConfigFilter axis_filter;
- ContextWrapper wrappedContext{context_};
+ ContextWrapper wrapped_context{context};
+ wrapped_context.SetSource(artifact.name);
- if (artifact.abi_group) {
- const std::string& group_name = artifact.abi_group.value();
-
- 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 << "'");
- return {};
- }
- filters->AddFilter(AbiFilter::FromAbiList(group->second));
+ if (!artifact.abis.empty()) {
+ filters->AddFilter(AbiFilter::FromAbiList(artifact.abis));
}
- if (artifact.screen_density_group) {
- const std::string& group_name = artifact.screen_density_group.value();
-
- 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 << "'");
- return {};
- }
-
- const std::vector<ConfigDescription>& densities = group->second;
- for(const auto& density_config : densities) {
+ if (!artifact.screen_densities.empty()) {
+ for (const auto& density_config : artifact.screen_densities) {
splits.preferred_densities.push_back(density_config.density);
}
}
- if (artifact.locale_group) {
- const std::string& group_name = artifact.locale_group.value();
- 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 << "'");
- return {};
- }
-
- const std::vector<ConfigDescription>& locales = group->second;
- for (const auto& locale : locales) {
+ if (!artifact.locales.empty()) {
+ for (const auto& locale : artifact.locales) {
axis_filter.AddConfig(locale);
}
splits.config_filter = &axis_filter;
}
- Maybe<AndroidSdk> sdk = GetAndroidSdk(artifact, config, context_->GetDiagnostics());
- if (sdk && sdk.value().min_sdk_version) {
- wrappedContext.SetMinSdkVersion(sdk.value().min_sdk_version.value());
+ if (artifact.android_sdk && artifact.android_sdk.value().min_sdk_version) {
+ wrapped_context.SetMinSdkVersion(artifact.android_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 {};
}
@@ -261,8 +254,7 @@
return table;
}
-bool MultiApkGenerator::UpdateManifest(const Artifact& artifact,
- const PostProcessingConfiguration& config,
+bool MultiApkGenerator::UpdateManifest(const OutputArtifact& artifact,
std::unique_ptr<XmlResource>* updated_manifest,
IDiagnostics* diag) {
const xml::XmlResource* apk_manifest = apk_->GetManifest();
@@ -301,10 +293,9 @@
versionCode->compiled_value = ResourceUtils::TryParseInt(std::to_string(new_version));
// Check to see if the minSdkVersion needs to be updated.
- Maybe<AndroidSdk> maybe_sdk = GetAndroidSdk(artifact, config, diag);
- if (maybe_sdk) {
+ if (artifact.android_sdk) {
// TODO(safarmer): Handle the rest of the Android SDK.
- const AndroidSdk& android_sdk = maybe_sdk.value();
+ const AndroidSdk& android_sdk = artifact.android_sdk.value();
if (xml::Element* uses_sdk_el = manifest_el->FindChild({}, "uses-sdk")) {
if (xml::Attribute* min_sdk_attr =
@@ -326,10 +317,7 @@
}
}
- if (artifact.screen_density_group) {
- auto densities = config.screen_density_groups.find(artifact.screen_density_group.value());
- CHECK(densities != config.screen_density_groups.end()) << "Missing density group";
-
+ if (!artifact.screen_densities.empty()) {
xml::Element* screens_el = manifest_el->FindChild({}, "compatible-screens");
if (!screens_el) {
// create a new element.
@@ -342,7 +330,7 @@
screens_el->GetChildElements().clear();
}
- for (const auto& density : densities->second) {
+ for (const auto& density : artifact.screen_densities) {
std::unique_ptr<xml::Element> screen_el = util::make_unique<xml::Element>();
screen_el->name = "screen";
const char* density_str = density.toString().string();
diff --git a/tools/aapt2/optimize/MultiApkGenerator.h b/tools/aapt2/optimize/MultiApkGenerator.h
index e6546ee..19f64cc 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.h
+++ b/tools/aapt2/optimize/MultiApkGenerator.h
@@ -17,6 +17,11 @@
#ifndef AAPT2_APKSPLITTER_H
#define AAPT2_APKSPLITTER_H
+#include <memory>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
#include "Diagnostics.h"
#include "LoadedApk.h"
#include "configuration/ConfigurationParser.h"
@@ -25,8 +30,9 @@
struct MultiApkGeneratorOptions {
std::string out_dir;
- configuration::PostProcessingConfiguration config;
+ std::vector<configuration::OutputArtifact> apk_artifacts;
TableFlattenerOptions table_flattener_options;
+ std::unordered_set<std::string> kept_artifacts;
};
/**
@@ -44,18 +50,17 @@
bool FromBaseApk(const MultiApkGeneratorOptions& options);
protected:
- virtual std::unique_ptr<ResourceTable> FilterTable(
- const configuration::Artifact& artifact,
- const configuration::PostProcessingConfiguration& config, const ResourceTable& old_table,
- FilterChain* chain);
+ virtual std::unique_ptr<ResourceTable> FilterTable(IAaptContext* context,
+ const configuration::OutputArtifact& artifact,
+ const ResourceTable& old_table,
+ FilterChain* chain);
private:
IDiagnostics* GetDiagnostics() {
return context_->GetDiagnostics();
}
- bool UpdateManifest(const configuration::Artifact& artifact,
- const configuration::PostProcessingConfiguration& config,
+ bool UpdateManifest(const configuration::OutputArtifact& artifact,
std::unique_ptr<xml::XmlResource>* updated_manifest, IDiagnostics* diag);
LoadedApk* apk_;
diff --git a/tools/aapt2/optimize/MultiApkGenerator_test.cpp b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
index 30c9146..e1d951f 100644
--- a/tools/aapt2/optimize/MultiApkGenerator_test.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
@@ -36,8 +36,7 @@
using ::aapt::configuration::Abi;
using ::aapt::configuration::AndroidSdk;
-using ::aapt::configuration::Artifact;
-using ::aapt::configuration::PostProcessingConfiguration;
+using ::aapt::configuration::OutputArtifact;
using ::aapt::test::GetValue;
using ::aapt::test::GetValueForConfig;
using ::aapt::test::ParseConfigOrDie;
@@ -48,7 +47,6 @@
using ::testing::PrintToString;
using ::testing::Return;
using ::testing::Test;
-using ::testing::_;
/**
* Subclass the MultiApkGenerator class so that we can access the protected FilterTable method to
@@ -60,11 +58,11 @@
: MultiApkGenerator(apk, context) {
}
- 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);
+ std::unique_ptr<ResourceTable> FilterTable(IAaptContext* context,
+ const configuration::OutputArtifact& artifact,
+ const ResourceTable& old_table,
+ FilterChain* filter_chain) override {
+ return MultiApkGenerator::FilterTable(context, artifact, old_table, filter_chain);
}
};
@@ -108,27 +106,13 @@
LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(19).Build();
- PostProcessingConfiguration empty_config;
- TableFlattenerOptions table_flattener_options;
FilterChain chain;
- Artifact x64 = test::ArtifactBuilder()
- .SetName("${basename}.${sdk}.apk")
- .SetDensityGroup("xhdpi")
- .SetAndroidSdk("v23")
- .Build();
-
- auto config = test::PostProcessingConfigurationBuilder()
- .SetLocaleGroup("en", {"en"})
- .SetAbiGroup("x64", {Abi::kX86_64})
- .SetDensityGroup("xhdpi", {"xhdpi"})
- .SetAndroidSdk("v23", AndroidSdk::ForMinSdk(23))
- .AddArtifact(x64)
- .Build();
+ OutputArtifact artifact = test::ArtifactBuilder().AddDensity(xhdpi_).SetAndroidSdk(23).Build();
MultiApkGeneratorWrapper generator{&apk, ctx.get()};
std::unique_ptr<ResourceTable> split =
- generator.FilterTable(x64, config, *apk.GetResourceTable(), &chain);
+ generator.FilterTable(ctx.get(), artifact, *apk.GetResourceTable(), &chain);
ResourceTable* new_table = split.get();
EXPECT_THAT(ValueForConfig(new_table, mdpi_), IsNull());
@@ -149,27 +133,13 @@
LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
- PostProcessingConfiguration empty_config;
- TableFlattenerOptions table_flattener_options;
FilterChain chain;
- Artifact x64 = test::ArtifactBuilder()
- .SetName("${basename}.${sdk}.apk")
- .SetDensityGroup("xhdpi")
- .SetAndroidSdk("v4")
- .Build();
-
- auto config = test::PostProcessingConfigurationBuilder()
- .SetLocaleGroup("en", {"en"})
- .SetAbiGroup("x64", {Abi::kX86_64})
- .SetDensityGroup("xhdpi", {"xhdpi"})
- .SetAndroidSdk("v4", AndroidSdk::ForMinSdk(4))
- .AddArtifact(x64)
- .Build();
+ OutputArtifact artifact = test::ArtifactBuilder().AddDensity(xhdpi_).SetAndroidSdk(4).Build();
MultiApkGeneratorWrapper generator{&apk, ctx.get()};;
std::unique_ptr<ResourceTable> split =
- generator.FilterTable(x64, config, *apk.GetResourceTable(), &chain);
+ generator.FilterTable(ctx.get(), artifact, *apk.GetResourceTable(), &chain);
ResourceTable* new_table = split.get();
EXPECT_THAT(ValueForConfig(new_table, mdpi_), IsNull());
@@ -188,23 +158,13 @@
LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
- PostProcessingConfiguration empty_config;
- TableFlattenerOptions table_flattener_options;
FilterChain chain;
- Artifact x64 =
- test::ArtifactBuilder().SetName("${basename}.${sdk}.apk").SetDensityGroup("xhdpi").Build();
-
- auto config = test::PostProcessingConfigurationBuilder()
- .SetLocaleGroup("en", {"en"})
- .SetAbiGroup("x64", {Abi::kX86_64})
- .SetDensityGroup("xhdpi", {"xhdpi"})
- .AddArtifact(x64)
- .Build();
+ OutputArtifact artifact = test::ArtifactBuilder().AddDensity(xhdpi_).Build();
MultiApkGeneratorWrapper generator{&apk, ctx.get()};
std::unique_ptr<ResourceTable> split =
- generator.FilterTable(x64, config, *apk.GetResourceTable(), &chain);
+ generator.FilterTable(ctx.get(), artifact, *apk.GetResourceTable(), &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/test/Builders.cpp b/tools/aapt2/test/Builders.cpp
index ecec63f..88897a8 100644
--- a/tools/aapt2/test/Builders.cpp
+++ b/tools/aapt2/test/Builders.cpp
@@ -25,7 +25,7 @@
using ::aapt::configuration::Abi;
using ::aapt::configuration::AndroidSdk;
-using ::aapt::configuration::Artifact;
+using ::aapt::configuration::ConfiguredArtifact;
using ::aapt::io::StringInputStream;
using ::android::StringPiece;
@@ -221,72 +221,32 @@
return doc;
}
-PostProcessingConfigurationBuilder& PostProcessingConfigurationBuilder::SetAbiGroup(
- const std::string& name, const std::vector<Abi>& abis) {
- config_.abi_groups[name] = abis;
- return *this;
-}
-
-PostProcessingConfigurationBuilder& PostProcessingConfigurationBuilder::SetLocaleGroup(
- const std::string& name, const std::vector<std::string>& locales) {
- auto& group = config_.locale_groups[name];
- for (const auto& locale : locales) {
- group.push_back(ParseConfigOrDie(locale));
- }
- return *this;
-}
-
-PostProcessingConfigurationBuilder& PostProcessingConfigurationBuilder::SetDensityGroup(
- const std::string& name, const std::vector<std::string>& densities) {
- auto& group = config_.screen_density_groups[name];
- for (const auto& density : densities) {
- group.push_back(ParseConfigOrDie(density));
- }
- return *this;
-}
-
-PostProcessingConfigurationBuilder& PostProcessingConfigurationBuilder::SetAndroidSdk(
- const std::string& name, const AndroidSdk& sdk) {
- config_.android_sdk_groups[name] = sdk;
- return *this;
-}
-
-PostProcessingConfigurationBuilder& PostProcessingConfigurationBuilder::AddArtifact(
- const Artifact& artifact) {
- config_.artifacts.push_back(artifact);
- return *this;
-}
-
-configuration::PostProcessingConfiguration PostProcessingConfigurationBuilder::Build() {
- return config_;
-}
-
ArtifactBuilder& ArtifactBuilder::SetName(const std::string& name) {
- artifact_.name = {name};
+ artifact_.name = name;
return *this;
}
-ArtifactBuilder& ArtifactBuilder::SetAbiGroup(const std::string& name) {
- artifact_.abi_group = {name};
+ArtifactBuilder& ArtifactBuilder::AddAbi(configuration::Abi abi) {
+ artifact_.abis.push_back(abi);
return *this;
}
-ArtifactBuilder& ArtifactBuilder::SetDensityGroup(const std::string& name) {
- artifact_.screen_density_group = {name};
+ArtifactBuilder& ArtifactBuilder::AddDensity(const ConfigDescription& density) {
+ artifact_.screen_densities.push_back(density);
return *this;
}
-ArtifactBuilder& ArtifactBuilder::SetLocaleGroup(const std::string& name) {
- artifact_.locale_group = {name};
+ArtifactBuilder& ArtifactBuilder::AddLocale(const ConfigDescription& locale) {
+ artifact_.locales.push_back(locale);
return *this;
}
-ArtifactBuilder& ArtifactBuilder::SetAndroidSdk(const std::string& name) {
- artifact_.android_sdk_group = {name};
+ArtifactBuilder& ArtifactBuilder::SetAndroidSdk(int min_sdk) {
+ artifact_.android_sdk = {AndroidSdk::ForMinSdk(min_sdk)};
return *this;
}
-configuration::Artifact ArtifactBuilder::Build() {
+configuration::OutputArtifact ArtifactBuilder::Build() {
return artifact_;
}
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 4cdfc33..2f83b78 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -25,6 +25,7 @@
#include "ResourceTable.h"
#include "ResourceValues.h"
#include "configuration/ConfigurationParser.h"
+#include "configuration/ConfigurationParser.internal.h"
#include "process/IResourceTableConsumer.h"
#include "test/Common.h"
#include "util/Maybe.h"
@@ -154,38 +155,19 @@
std::unique_ptr<xml::XmlResource> BuildXmlDomForPackageName(IAaptContext* context,
const android::StringPiece& str);
-class PostProcessingConfigurationBuilder {
- public:
- PostProcessingConfigurationBuilder() = default;
-
- PostProcessingConfigurationBuilder& SetAbiGroup(const std::string& name,
- const std::vector<configuration::Abi>& abis);
- PostProcessingConfigurationBuilder& SetLocaleGroup(const std::string& name,
- const std::vector<std::string>& locales);
- PostProcessingConfigurationBuilder& SetDensityGroup(const std::string& name,
- const std::vector<std::string>& densities);
- PostProcessingConfigurationBuilder& SetAndroidSdk(const std::string& name,
- const configuration::AndroidSdk& sdk);
- PostProcessingConfigurationBuilder& AddArtifact(const configuration::Artifact& artifact);
- configuration::PostProcessingConfiguration Build();
-
- private:
- configuration::PostProcessingConfiguration config_;
-};
-
class ArtifactBuilder {
public:
ArtifactBuilder() = default;
ArtifactBuilder& SetName(const std::string& name);
- ArtifactBuilder& SetAbiGroup(const std::string& name);
- ArtifactBuilder& SetDensityGroup(const std::string& name);
- ArtifactBuilder& SetLocaleGroup(const std::string& name);
- ArtifactBuilder& SetAndroidSdk(const std::string& name);
- configuration::Artifact Build();
+ ArtifactBuilder& AddAbi(configuration::Abi abi);
+ ArtifactBuilder& AddDensity(const ConfigDescription& density);
+ ArtifactBuilder& AddLocale(const ConfigDescription& locale);
+ ArtifactBuilder& SetAndroidSdk(int min_sdk);
+ configuration::OutputArtifact Build();
private:
- configuration::Artifact artifact_;
+ configuration::OutputArtifact artifact_;
};
} // namespace test
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/locked_region_code_injection/Android.bp b/tools/locked_region_code_injection/Android.bp
index 6dd6059..5f81a2e 100644
--- a/tools/locked_region_code_injection/Android.bp
+++ b/tools/locked_region_code_injection/Android.bp
@@ -1,4 +1,4 @@
-java_library_host {
+java_binary_host {
name: "lockedregioncodeinjection",
manifest: "manifest.txt",
srcs: ["src/**/*.java"],
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/cpp/main.cpp b/tools/streaming_proto/cpp/main.cpp
index 4779020..745b3dc 100644
--- a/tools/streaming_proto/cpp/main.cpp
+++ b/tools/streaming_proto/cpp/main.cpp
@@ -85,11 +85,17 @@
return message.options().GetExtension(stream_msg).enable_fields_mapping();
}
+static inline bool
+should_generate_fields_mapping_recursively(const DescriptorProto& message) {
+ return message.options().GetExtension(stream_msg).enable_fields_mapping_recursively();
+}
+
static void
-write_message(stringstream& text, const DescriptorProto& message, const string& indent)
+write_message(stringstream& text, const DescriptorProto& message, const string& indent, bool genMapping)
{
int N;
const string indented = indent + INDENT;
+ genMapping |= should_generate_fields_mapping_recursively(message);
text << indent << "// message " << message.name() << endl;
text << indent << "namespace " << message.name() << " {" << endl;
@@ -103,7 +109,7 @@
// Nested classes
N = message.nested_type_size();
for (int i=0; i<N; i++) {
- write_message(text, message.nested_type(i), indented);
+ write_message(text, message.nested_type(i), indented, genMapping);
}
// Fields
@@ -112,7 +118,7 @@
write_field(text, message.field(i), indented);
}
- if (should_generate_fields_mapping(message)) {
+ if (genMapping | should_generate_fields_mapping(message)) {
N = message.field_size();
text << indented << "const int _FIELD_COUNT = " << N << ";" << endl;
text << indented << "const char* _FIELD_NAMES[" << N << "] = {" << endl;
@@ -161,7 +167,7 @@
N = file_descriptor.message_type_size();
for (size_t i=0; i<N; i++) {
- write_message(text, file_descriptor.message_type(i), "");
+ write_message(text, file_descriptor.message_type(i), "", false);
}
for (vector<string>::iterator it = namespaces.begin(); it != namespaces.end(); it++) {
diff --git a/tools/streaming_proto/stream.proto b/tools/streaming_proto/stream.proto
index c081209..e9b24a8 100644
--- a/tools/streaming_proto/stream.proto
+++ b/tools/streaming_proto/stream.proto
@@ -24,6 +24,9 @@
message MessageOptions {
// creates a mapping of field names of the message to its field ids
optional bool enable_fields_mapping = 1;
+
+ // creates mapping between field names to its field ids and recursively for its submessages.
+ optional bool enable_fields_mapping_recursively = 2;
}
extend google.protobuf.MessageOptions {
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/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index abbb82a..0dd964c 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -164,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();
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 558004c..a158d94 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -3488,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;
}
/**
@@ -3538,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;
}
/**
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/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/services/core/java/com/android/server/timezone/ClockHelper.java b/wifi/java/android/net/wifi/rtt/ResponderConfig.aidl
similarity index 75%
copy from services/core/java/com/android/server/timezone/ClockHelper.java
copy to wifi/java/android/net/wifi/rtt/ResponderConfig.aidl
index 353728a..fd3988a 100644
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ b/wifi/java/android/net/wifi/rtt/ResponderConfig.aidl
@@ -14,12 +14,6 @@
* limitations under the License.
*/
-package com.android.server.timezone;
+package android.net.wifi.rtt;
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
-
- long currentTimestamp();
-}
+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/java/android/net/wifi/rtt/WifiRttManager.java b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
index 735e872..b4c690f 100644
--- a/wifi/java/android/net/wifi/rtt/WifiRttManager.java
+++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
@@ -41,7 +41,7 @@
*
* @hide RTT_API
*/
-@SystemService(Context.WIFI_RTT2_SERVICE)
+@SystemService(Context.WIFI_RTT_RANGING_SERVICE)
public class WifiRttManager {
private static final String TAG = "WifiRttManager";
private static final boolean VDBG = false;
diff --git a/wifi/java/android/net/wifi/rtt/package.html b/wifi/java/android/net/wifi/rtt/package.html
index 221b94b..a0d407a 100644
--- a/wifi/java/android/net/wifi/rtt/package.html
+++ b/wifi/java/android/net/wifi/rtt/package.html
@@ -5,7 +5,7 @@
<p>The primary entry point to Wi-Fi RTT capabilities is the
{@link android.net.wifi.rtt.WifiRttManager} class, which is acquired by calling
{@link android.content.Context#getSystemService(String)
- Context.getSystemService(Context.WIFI_RTT_SERVICE)}</p>
+ Context.getSystemService(Context.WIFI_RTT_RANGING_SERVICE)}</p>
<p>Some APIs may require the following user permissions:</p>
<ul>
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;